13 KiB
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.mdvsprogression.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,furthestNodeReachedupdates, but NO unlock evaluation. - Contradiction: "No partial rewards" implies gold is NOT awarded/recorded on loss. Progression explicitly expects
goldEarnedon loss runs. - Resolution needed: Clarify the intended design. Two options:
- (A) Loss runs do NOT record gold in LifetimeStats → remove
totalGoldEarned += goldEarnedfrom 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"
- (A) Loss runs do NOT record gold in LifetimeStats → remove
🔴 [C2] One-directional dependency: Tower Assembly ↔ Progression
- Documents:
tower-assembly.mdvsprogression.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.mdvstower-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.mdis 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 = 9999consistently — 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→ callsProgression.RecordRunEnd(runStats) - Progression updates
LifetimeStats.totalGoldEarned += goldEarned - But
OnUnlockedEventArgscarries onlyUnlockResult[]— 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)
UnlockedEventArgscarries agoldEarnedThisRunfield, or (B) Node System provides gold data directly to Run End screen (bypass Progression), or (C) Run End screen queriesProgression.GetLastRunGold()(add this method)
🔴 [G3] Undefined behavior: does RecordRunEnd fire on loss runs?
- Documents:
node-system.mdvsprogression.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
RecordRunEndon loss, Progression's loss-path AC is unreachable - Resolution needed: Clarify: does Node System call
RecordRunEndon 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) AddRandomCompsusesInventoryGenerationComponentwith 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:
- Node System: Combat victory at Boss node → fires
NodeCompleteEventArgswithCombatWon=true - Node System: Calls
Progression.RecordRunEnd(runStats)with{goldEarned, nodesCompleted=10, bossDefeated=true, ...} - Progression: Updates
LifetimeStats→ evaluates unlocks → firesUnlockedEventArgswithUnlockResult[] - 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:
UnlockedEventArgscarries nogoldEarnedfield - 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
RunEndwithbossDefeated=false - Does
RecordRunEndfire? (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:
- C1: "No partial rewards" vs. Progression loss-path gold — design decision required
- G1: Exponential boss HP vs. linear player power — hard wall makes boss unbeatable after ~cycle 5–7
- 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
- C1: Decide: do loss runs record gold in LifetimeStats? Update both Node System and Progression GDDs accordingly
- G1: Redesign boss scaling formula — change from exponential to logarithmic, or add player catch-up mechanic, or cap boss cycles
- G2: Add
goldEarnedThisRuntoUnlockedEventArgs, OR have Node System provide gold directly to Run End screen - G3: Clarify whether Node System calls
RecordRunEndon loss. Update Progression SR2 and AC to match. - C2: Either add Tower Assembly as soft upstream to Progression (with interface), or remove the speculative reference from Tower Assembly GDD
- C4: Resolve Node System Open Question #3 now that Shop GDD is complete