geometry-tower-defense/design/gdd/gdd-cross-review-2026-04-30.md

141 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Cross-GDD Review Report
> **Date**: 2026-04-30
> **Reviewer**: Claude Code (consistency + design theory agents)
> **GDDs Reviewed**: 6 (node-system.md, tower-assembly.md, shop.md, event-system.md, progression.md, CombatNodeArchitecture.md)
> **Systems Covered**: Node System, Combat System, Tower Assembly, Shop System, Event System, Progression
---
## Consistency Issues
### Warnings
⚠️ **[C-W1] Tower Assembly Dependency Direction Is Inverted**
- **Files**: `tower-assembly.md` (Dependencies, line 207)
- Tower Assembly lists **Node System as an upstream (hard) dependency** — but the relationship is reversed. Node System **calls into** Tower Assembly during Assembly Phase. Tower Assembly is the **downstream** service, not the upstream.
- **Correct model**: Node System → (calls) → Tower Assembly. Tower Assembly is downstream.
- **Impact**: Logical error in dependency model. Does not block implementation.
- **Fix**: Swap direction — Tower Assembly should list Combat System as downstream consumer, and remove Node System as upstream dependency.
⚠️ **[C-W2] RunStats.goldEarned Loss-Path Contract Not Formally Sealed**
- **Files**: `node-system.md` (Edge Cases), `progression.md` (AC5b), `CombatNodeArchitecture.md` (§12.3.2)
- Design intent is **consistent**: zero gold on loss. `CombatNodeArchitecture.md §12.3.2` correctly states `GainedGold = 0` on loss, and `node-system.md` Edge Cases states "no partial rewards."
- However: `progression.md` AC5b says `totalGoldEarned += goldEarned` on loss — correct only if `goldEarned == 0`. The **RunStats schema** (`goldEarned >= 0`) allows non-zero values without a loss-specific constraint.
- No AC in `node-system.md` formally seals: `runStats.goldEarned == 0` on loss.
- **Impact**: Design intent is consistent; GDD contract is not airtight. A future implementer could introduce a non-zero gold-on-loss path without violating any AC.
- **Fix**: Add explicit AC in node-system.md: `"**GIVEN** the player loses Combat at any node, **WHEN** `RecordRunEnd` is called, **THEN** `runStats.goldEarned == 0`."`
⚠️ **[C-W3] Event System Does Not List Node System as Dependency Source for BossBonusGold**
- **Files**: `event-system.md` (Dependencies, line 178), `node-system.md` (line 122, line 223)
- `BossBonusGold = 200` is declared in `node-system.md` but `event-system.md` does not list `node-system.md` as a dependency source for this value.
- Not a functional issue — `BossBonusGold` is not referenced in Event System mechanics.
- **Fix**: Add `BossBonusGold` sourcing note in `event-system.md` Dependencies if the value is ever used in event design.
---
## Game Design Issues
### Warnings
⚠️ **[G-W1] Tag System GDD Does Not Exist — Tag Stacking Is Unconstrained (HIGHEST PRIORITY)**
- **Files**: `tower-assembly.md` (TagAggregation), `design/gdd/tag-system.md` (**DOES NOT EXIST**)
- `TowerAssembly.AggregateTowerTags()` produces `TotalStack = occurrence count (13)` per tag. The GDD explicitly states: "the effective power multiplier semantics of this count... are defined in the Tag System GDD."
- **The Tag System GDD does not exist in the codebase.**
- **Structural dominant strategy**: If `Stack=3` is strictly better than `Stack=2` or `Stack=1` for any tag, the optimal tower always uses 3 copies of the best available tag. The "optimization puzzle" has a single solution.
- **Fix**: Write `design/gdd/tag-system.md` before implementing Tower Assembly. Define stacking semantics (linear? diminishing returns? multiplicative ceiling?).
⚠️ **[G-W2] Event Rewards Share Rarity Budget with Shop — No Distinct Tier**
- **Files**: `event-system.md` (ER4: AddRandomComps), `shop.md` (SR1), `progression.md` (pool unlock chain)
- `AddRandomComps` calls `InventoryGenerationComponent.BuildEventRewardComponents()` — the same generation pipeline as shop.
- Events cannot reward a rarity the player hasn't unlocked in Progression.
- Event System pillar ("narrative surprise and meaningful stakes") is undermined when the reward tier is identical to shop.
- **Fix**: Consider a separate event rarity budget (e.g., events drop at most Blue even if player has Red unlocked), or a distinct reward category.
⚠️ **[G-W3] Sell Price at ~50% Actively Discourages Experimentation**
- **Files**: `shop.md` (SR6, Formula 2), `tower-assembly.md` (Fantasy line 20)
- Tower Assembly fantasy: "free reconfiguration," "optimization mastery under constraint"
- Shop sell formula: `Round((minPrice + maxPrice) / 2.0f)` — ~50% of max buy price
- Player who buys a White component for 100, tries it, sells it back gets 50. Half their experiment cost is destroyed.
- Free disassemble partially offsets this — but if inventory is full and player wants to try a new component, they must sell something.
- **Fix**: Make sell ratio a tunable knob (recommend 6070%) or add a component enhancement sink that uses excess components.
⚠️ **[G-W4] Assembly Phase Has 5 Simultaneous Panels — Cognitive Load Risk**
- **Files**: `tower-assembly.md` (Assembly Phase Screen, UI Requirements)
- Panels: Inventory Grid + 3 Assembly Slots + Assembled Towers + Combat Roster + Next Node Preview
- The GDD's own design note: "Ready button is enabled and clicking it proceeds... without modification." — the designed workaround is to click Ready when nothing needs doing.
- **Structural problem**: Players who understand the game will click Ready almost every time after the first few runs. The elaborate UI becomes noise.
- **Fix**: Merge Assembled Towers panel with Combat Roster (single "Your Towers" panel with roster checkboxes), or introduce a "Quick Assemble" mode that hides unused panels.
⚠️ **[G-W5] "Build Toward the Boss" Fantasy Conflicts with Boss Scaling Formula**
- **Files**: `tower-assembly.md` (Fantasy line 22), `node-system.md` (Boss HP formula)
- Tower Assembly fantasy: "each assembly decision accumulates toward the final confrontation; the boss fight is where build quality is ultimately tested."
- `BossEffectiveHp = BaseHp × 2^completedLoopCount` — Boss HP scales with rounds survived, not player power.
- Better build → faster kill → fewer loops survived → lower effective HP. The boss IS a test of kill speed, not raw survivability.
- The stated fantasy implies build quality = being powerful enough to win, not kill-speed pressure.
- **Fix**: Revise Tower Assembly Fantasy line 22 to reflect kill-speed pressure, not "build quality tested."
⚠️ **[G-W6] Difficulty Spike at Normal→Hard Before Component Pool Catches Up**
- **Files**: `progression.md` (pool unlock chain), `node-system.md` (Plain theme node sequence)
- Green pool unlocks on first Normal win. Hard difficulty unlocks after defeating Boss on Normal.
- Player enters Hard with only Green components. The first 4 Hard combat nodes are fought with inadequate tools.
- **Fix**: Consider starting Green pool available before first win, or give Hard difficulty a more generous starting loadout.
⚠️ **[G-W7] Gold Cap (9999) Is Effectively Unreachable in Normal Play**
- **Files**: `shop.md` (MaxPlayerGold), `node-system.md` (per-run gold ~1100)
- ~1100 gold per full winning run. 9999 cap. ~9 wins to cap, assuming minimal spending.
- With free disassemble and no repair mechanism, spending pressure is low. A skilled player accumulates excess gold with no outlet.
- **Fix**: Consider a prestige mechanic that converts excess gold into permanent upgrades, or significantly lower `MaxPlayerGold`.
---
## Cross-System Scenario Issues
**Scenarios walked:** 1 (Full Run End chain)
### Full Winning Run — RunEnd Chain
1. Node System: Boss defeated → fires `NodeCompleteEventArgs(CombatWon=true)`
2. Node System → `Progression.RecordRunEnd(runStats)` with `{goldEarned, nodesCompleted=10, bossDefeated=true, coinsEarned}`
3. Progression: `LifetimeStats` updated → unlock evaluation → `UnlockedEventArgs` with `UnlockResult[]`
4. UI / Run End Screen: Toast popup for new unlocks
**Issues found:**
⚠️ **G-W7 (display gap)**: Run End Victory screen cannot display "Gold earned this run" without a data path. `UnlockedEventArgs` carries no `goldEarnedThisRun` field. This was G2 in the 2026-04-29 review — flagged as blocking — but is a **display gap, not a crash**. The screen shows 0 gold implicitly. Recommend adding `goldEarnedThisRun` to `UnlockedEventArgs` for UX completeness.
---
## GDDs Flagged for Revision
| GDD | Reason | Type | Priority |
|-----|--------|------|----------|
| `tower-assembly.md` | C-W1: dependency direction inverted; G-W1: Tag System GDD missing; G-W5: boss fantasy conflict | Consistency + Design Theory | **High** |
| `event-system.md` | G-W2: event rarity budget not distinct from shop | Design Theory | Medium |
| `shop.md` | G-W3: sell ratio tunable knob; G-W7: gold cap tuning | Design Theory | Medium |
| `node-system.md` | C-W2: loss gold AC gap; G-W6: difficulty spike | Consistency + Design Theory | Medium |
---
## Verdict: **CONCERNS**
No blocking issues — no system is mechanically broken. All 6 systems are implementable and internally coherent.
Warnings present — 7 warnings and 1 scenario info item. These should be resolved before or during implementation but do not prevent architecture work from beginning.
**Most urgent**: G-W1 (Tag System GDD missing) — without it, `TagAggregation` output is undefined and Tower Assembly cannot be fully implemented.
---
## Recommended Actions
1. **G-W1 (HIGHEST)**: Write `design/gdd/tag-system.md` — define tag stacking semantics before implementing Tower Assembly
2. **C-W1**: Fix Tower Assembly dependency direction — swap Node System from upstream to downstream
3. **C-W2**: Add formal AC in node-system.md sealing `runStats.goldEarned == 0` on loss
4. **G-W5**: Revise Tower Assembly Fantasy line 22 — "build toward the boss" should reflect kill-speed pressure
5. **G-W2**: Event System — consider separate rarity budget for event rewards
6. **G-W3**: Shop — make sell ratio a tunable knob
7. **G-W6**: Progression — address Normal→Hard difficulty spike before component pool upgrade
8. **G-W7**: Shop — consider gold cap tuning or prestige mechanic
9. **C-W3**: Event System — add BossBonusGold sourcing reference to Node System