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

10 KiB
Raw Blame History

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** RecordRunEndis 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.


  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