# Cross-GDD Review Report > **Date**: 2026-04-29 > **Reviewer**: Consistency Agent + Game Design Holism Agent > **GDDs Reviewed**: 5 (node-system.md, shop.md, tower-assembly.md, event-system.md, progression.md) > **Systems Covered**: Node System, Shop System, Tower Assembly, Event System, Progression --- ## Consistency Issues ### Blocking (must resolve before architecture) 🔴 **[C1] Rule contradiction: "no partial rewards on loss" vs. Progression accepting gold on loss** - **Documents**: `node-system.md` vs `progression.md` - **Node System** (Edge Cases): "Any combat loss: Run ends in failure immediately. No partial rewards are awarded." - **Progression** (SR2 + AC): `RecordRunEnd()` is called on every run end (win or loss). On loss: `totalRunsStarted++`, `totalGoldEarned += goldEarned`, `furthestNodeReached` updates, but NO unlock evaluation. - **Contradiction**: "No partial rewards" implies gold is NOT awarded/recorded on loss. Progression explicitly expects `goldEarned` on loss runs. - **Resolution needed**: Clarify the intended design. Two options: - (A) Loss runs do NOT record gold in LifetimeStats → remove `totalGoldEarned += goldEarned` from loss path in Progression AC - (B) Loss runs DO record gold stats (only unlocks are withheld) → Node System's "no partial rewards" must be clarified to mean "no unlocks" not "no gold tracking" --- 🔴 **[C2] One-directional dependency: Tower Assembly ↔ Progression** - **Documents**: `tower-assembly.md` vs `progression.md` - **Tower Assembly** (Dependencies): "Progression — May read aggregate tower assembly stats across runs. Pending Progression GDD." - **Progression** (Dependencies): Lists Node System and Shop System as upstream. Does NOT list Tower Assembly. - **Impact**: If Tower Assembly wanted to persist aggregate stats (e.g., "total towers assembled lifetime"), no interface contract exists. Progression has no `RecordTowerAssemblyStats()` method. - **Resolution needed**: Either (A) Progression adds Tower Assembly as a soft upstream dependency with a defined read interface, or (B) Tower Assembly's reference to Progression is removed/clarified as speculative. --- ### Warnings ⚠️ **[C3] Bidirectionality gap: Node System → Tower Assembly (soft vs. hard mismatch)** - **Documents**: `node-system.md` vs `tower-assembly.md` - Node System marks Tower Assembly as **Soft/provisional** in its Dependencies. - Tower Assembly marks Node System as **Hard** upstream. - This is a directionality mismatch — the softer designation should flow one way consistently. - **Not blocking**: Tower Assembly's treatment of Node System as hard is likely correct; Node System's soft marking may be residual uncertainty from before Tower Assembly was designed. ⚠️ **[C4] Shop System GDD status in Node System is stale** - **Documents**: `node-system.md` (Open Questions #3) - Node System marks Shop System GDD as "blocking — interface contract pending alignment." - However, `shop.md` is now **Designed** (complete design exists). - Node System's Open Question #3 flag is stale. - **Resolution**: Node System Open Question #3 should be resolved now that Shop GDD exists. ⚠️ **[C5] Tuning Knob ownership: MaxPlayerGold shared across 3 GDDs** - **Documents**: `shop.md`, `event-system.md`, `progression.md` - All three reference `MaxPlayerGold = 9999` consistently — no value conflict. - However, no single GDD formally declares itself the **owner** of this constant. - Entity registry correctly sources it from `shop.md`. - **Recommendation**: Document in Shop GDD that it is the authoritative owner of `MaxPlayerGold`. --- ## Game Design Issues ### Blocking 🔴 **[G1] Exponential boss HP vs. linear player power — indefinite gap creates a hard wall** - **Documents**: `node-system.md` + `tower-assembly.md` - `BossEffectiveHp = BaseHp × 2^(completedLoopCount)` — exponential in boss cycles survived - Player tower stats: `statValue[i] = baseValue + perLevel × i` — linear, capped at 5 levels - After ~5–7 boss cycles, boss HP doubles so fast that even max-rarity max-level towers cannot deal enough damage before the boss outscales - The game becomes mathematically unbeatable at high loop counts regardless of build quality - **This is not a difficulty curve — it is a hard wall** - **Resolution needed**: Add a boss cycle cap, or add a player power catch-up mechanic (e.g., each boss cycle also grants a temporary attack buff, or boss HP scaling changes to logarithmic rather than exponential). Alternatively, redefine "VictoryType" to not involve looping, removing the exponential scaling trigger. --- 🔴 **[G2] Run End Screen cannot display gold earned this run — undefined data flow** - **Documents**: `node-system.md` + `progression.md` - Node System fires `RunEnd` → calls `Progression.RecordRunEnd(runStats)` - Progression updates `LifetimeStats.totalGoldEarned += goldEarned` - But `OnUnlockedEventArgs` carries only `UnlockResult[]` — NOT the run's gold amount - Run End Victory screen should show "Gold earned this run" — but no interface provides this data - **Resolution needed**: Either (A) `UnlockedEventArgs` carries a `goldEarnedThisRun` field, or (B) Node System provides gold data directly to Run End screen (bypass Progression), or (C) Run End screen queries `Progression.GetLastRunGold()` (add this method) --- 🔴 **[G3] Undefined behavior: does RecordRunEnd fire on loss runs?** - **Documents**: `node-system.md` vs `progression.md` - Progression SR2: "`RecordRunEnd()` is called on every run end (win or loss)" - Node System Edge Case: "Any combat loss: Run ends in failure immediately" — no mention of calling `RecordRunEnd` - Progression AC explicitly covers loss runs (stats update, no unlocks) - But if Node System never calls `RecordRunEnd` on loss, Progression's loss-path AC is unreachable - **Resolution needed**: Clarify: does Node System call `RecordRunEnd` on loss? If yes — Node System GDD must document this. If no — Progression's loss-run AC is unreachable and must be revised. --- ### Warnings ⚠️ **[G4] Unbounded gold accumulation — no sink between runs** - **Documents**: `node-system.md` + `shop.md` - Per full winning run: ~600 (combat) + 300 (boss level) + 200 (boss bonus) = ~1100 gold - With `MaxPlayerGold = 9999`, a player needs ~9 wins to cap out - Once at cap, excess gold from combat is discarded — additional survival is not rewarded - No sink between runs: no repair, no permanent upgrades, no sacrifice mechanic - **Risk**: Short optimized runs may be more rewarding than long successful ones; endgame economy becomes meaningless - **Recommendation**: Consider a meta-gold sink (permanent repair station, unlock purchases, or cosmetic unlocks) to recycle late-game gold ⚠️ **[G5] Multiple systems claim to be the primary progression loop** - **Documents**: All 5 GDDs - Node System: "tactician executing a plan" — navigates the run - Tower Assembly: "puzzle solver, cleverness" — builds power - Shop: "tactical urgency, deliberate investment" — resource decisions - Event: "narrative surprise, meaningful stakes" — variety - Progression: "relentless collection" — meta motivation - **Risk**: Without a declared primary loop, players optimize the wrong thing - **Recommendation**: Explicitly designate Tower Assembly as the core tactical loop; Node System as the structural frame; Shop/Event as the decision points; Progression as the meta-reward ⚠️ **[G6] Component Tag stacking — potential dominant strategy** - **Documents**: `tower-assembly.md` - R7: No compatibility constraints between component types - Tags aggregate with stack counts merging across 3 components - Optimal strategy: collect 3 copies of the best tag, stack it - **Risk**: The "puzzle" of tower assembly may have a trivially discoverable dominant solution - **Recommendation**: Consider adding anti-synergy rules (e.g., same tag on 3 components reduces effectiveness) or explicit trade-offs to maintain build diversity ⚠️ **[G7] Lossy economy (sell ~50% of buy) discourages experimentation** - **Documents**: `shop.md` - Sell price = midpoint of `[MinPrice, MaxPrice]` ≈ 50% of average buy - Repeated buy-sell cycles destroy gold - Players hoard components rather than experiment - **Risk**: Reduces strategic depth; players avoid build diversity - **Recommendation**: Consider a higher sell ratio (e.g., 60–70%) or a component enhancement sink to make exploration more affordable ⚠️ **[G8] Event rewards use same rarity budget as shop — no distinct reward tier** - **Documents**: `event-system.md` + `shop.md` (OQ5) - `AddRandomComps` uses `InventoryGenerationComponent` with identical rarity budget to shop - Events offer no higher-tier rewards than shop can provide - **Risk**: Events feel mathematically equivalent to additional shop visits; "genuine dilemma" fantasy may be undermined - **Recommendation**: Consider a separate event rarity budget (e.g., events drop 1 tier lower than equivalent shop purchase) to give events a distinct identity ⚠️ **[G9] Assembly Phase has 5 simultaneous information panels** - **Documents**: `tower-assembly.md` - During Assembly Phase: Inventory Grid + Tower Slots + Assembled Towers Panel + Combat Roster + Next Node Preview - **Risk**: Cognitive overload for new players - **Recommendation**: Consider a tabbed or sequenced interface rather than all panels visible simultaneously --- ## Cross-System Scenario Issues **Scenario: Player completes a winning run — full RunEnd chain** ### Steps: 1. **Node System**: Combat victory at Boss node → fires `NodeCompleteEventArgs` with `CombatWon=true` 2. **Node System**: Calls `Progression.RecordRunEnd(runStats)` with `{goldEarned, nodesCompleted=10, bossDefeated=true, ...}` 3. **Progression**: Updates `LifetimeStats` → evaluates unlocks → fires `UnlockedEventArgs` with `UnlockResult[]` 4. **UI / Run End Screen**: Receives `OnUnlockedEventArgs` → shows toast for new unlocks ### Issues found: 🔴 **G2 (already flagged above)**: Run End screen cannot display gold earned this run - Step 3: `UnlockedEventArgs` carries no `goldEarned` field - Run End Victory screen should show gold earned — no data path defined 🔴 **G3 (already flagged above)**: Ambiguous whether loss runs call `RecordRunEnd` - If loss path does not call `RecordRunEnd`, steps 2–3 never occur on loss ⚠️ **Scenario: Player reaches Boss but loses** - Node System fires `RunEnd` with `bossDefeated=false` - Does `RecordRunEnd` fire? (G3 ambiguity) - If yes: LifetimeStats records `furthestNodeReached=9`, no unlocks - If no: Partial run progress is lost, player gets no credit for reaching node 9 ⚠️ **Scenario: Multiple unlocks fire simultaneously** - Step 3: `UnlockResult[]` can contain multiple items - Step 4: Toast popup shows all — good - But no priority ordering if unlocks are from different categories (e.g., Difficulty + Theme simultaneously) - **Info**: Not a blocker; worth documenting expected ordering --- ## GDDs Flagged for Revision | GDD | Reason | Type | Priority | |-----|--------|------|----------| | `node-system.md` | C1/C3/C4: Stale Open Question #3, ambiguous loss behavior, "no partial rewards" contradicts Progression's loss-path AC | Consistency + Design Theory | **High** | | `progression.md` | C1: Loss-run gold recording contradicts Node System's "no partial rewards"; G3: loss run behavior undefined | Consistency + Design Theory | **High** | | `tower-assembly.md` | C2: Progression dependency is orphaned (one-directional); G6: Tag stacking dominant strategy risk | Consistency + Design Theory | Medium | --- ## Verdict: **CONCERNS** Three blocking issues must be resolved before architecture begins: 1. **C1**: "No partial rewards" vs. Progression loss-path gold — design decision required 2. **G1**: Exponential boss HP vs. linear player power — hard wall makes boss unbeatable after ~cycle 5–7 3. **G2/G3**: Undefined data flow for Run End screen gold display + ambiguous loss run behavior Warnings (G4–G9) are advisory and should be addressed before implementation but do not block architecture. --- ## Recommended Actions 1. **C1**: Decide: do loss runs record gold in LifetimeStats? Update both Node System and Progression GDDs accordingly 2. **G1**: Redesign boss scaling formula — change from exponential to logarithmic, or add player catch-up mechanic, or cap boss cycles 3. **G2**: Add `goldEarnedThisRun` to `UnlockedEventArgs`, OR have Node System provide gold directly to Run End screen 4. **G3**: Clarify whether Node System calls `RecordRunEnd` on loss. Update Progression SR2 and AC to match. 5. **C2**: Either add Tower Assembly as soft upstream to Progression (with interface), or remove the speculative reference from Tower Assembly GDD 6. **C4**: Resolve Node System Open Question #3 now that Shop GDD is complete