final fix - xopherdeep/do-it-for-the-xp GitHub Wiki

Final review — the one fix wave (findings with the lead's rulings)

Branch feat/classic-temples-2 (worktree /home/xopher/www/x/do-it-for-the-xp/.claude/worktrees/feat+classic-temples-2). The final whole-branch review (opus) said "Ready to merge: with fixes". The PR auto-merges on a green CI, so these must land first. TDD, one spec at a time, small commits.

1. Critical — older Temple Creator pits drop the hero onto themselves in a loop

Review: "src/lib/services/temples/roomInteractions/hazards.ts:45-61, 84 and the solver at src/lib/engine/dungeons/generator/templeGraph.ts:303-316. From 2025-12-28 until commit 7c104f53 (2026-10-13) the Creator gave every new travel room, pits included, targetLevel: <its own floor>, targetCoords: {x:0, y:0}; the later cleanup (seedTravelTargets, roomContent.ts:230) clears this only on stairs. Before this branch pits ignored both fields. Now pitFloor accepts any floor the temple has, including the pit's own, so hasFloorBelow is true even in a one-floor temple; arriveOn(own floor, [(0,0), ctx.position, ...]) puts the hero back on the pit when (0,0) is a wall (the usual case); the moved: true outcome calls arrive() -> onEnterRoom(pit) -> falls again, 5 HP each fall until 'defeated' sends the hero to the Hospital. Probe: a one-floor layout with a seeded pit gives the solver the door 1F:1,1 -> 1F:1,1." RULING: in BOTH pitFloor (engine) and linkPits (solver), honour targetLevel only when it names an existing floor strictly below the pit (floorHeight/the climbing order), and read targetCoords only then; otherwise use the old rule exactly (next floor down: same cell, then first stairs up; in a one-floor temple the pit bruises once as before). Engine and solver must agree when the named floor does not exist (this also settles the deferred minor "a pit naming a non-existent floor"). Specs (engine in RoomInteractions.spec or the hazards spec, solver in TempleSolver.spec): a pit carrying the old seed (own floor, {x:0,y:0}) behaves exactly as before in a one-floor and a two-floor temple; a pit naming a missing floor behaves the same in engine and solver; the existing targeted-pit tests stay green. Also let seedTravelTargets (roomContent.ts) clear the own-floor seed on pits, as it does on stairs, with a test.

2. Important — open the drop when the hero comes back from a won fight

Review: "useRoomOutcomes.ts:220 (the takeDrop case), TempleGrounds.ts. The spec: 'On a win the beast drops it: the hero takes it through the chest reveal on returning to the room.' Today nothing opens on return; the hero must open the room sheet and tap 'Take it'. The new Wind has 6 key drops; M004 and M005 flank the entrance and the only way north is a locked door; Quick Start puts tonight's first two quests exactly in those two rooms. A 6-year-old who walks off after winning meets 'You need a key to unlock this door!' with no clue." RULING: when the run reopens on a fight room whose drop is waiting (the battle return), call showDropReveal() once for that room. Put it in useRoomOutcomes or useTempleEntry (TempleGrounds.ts is at 500 lines: do not grow it). Do not re-open it on later arrivals in the same visit if the hero dismissed it (the sheet's "Take it" stays). Spec: the composable/outcome test that a battle return onto a won fight with a waiting drop opens the drop reveal, and that a plain arrival on a room whose fight is still live does not.

3. Important — Quick Start families never receive the new Wind

Review: "quickStartTemple.ts:217 together with importAllTemples.ts:108-109: runQuickStartTemple saves the Wind record with questIds placed and keeps the old seedSignature; planSeedSync then reads the copy as 'edited' forever. Every family that used Quick Start (the onboarding entry since 2026-10-18) keeps the Howling Spire, and every later Wind change too. No spec runs Quick Start against the shipped Wind (specs moved to windBeforeEagle); on the Eagle it places M005, M004 and m006, and m006 sits behind the entrance's locked door." RULING: a stored copy whose ONLY difference from its seeded layout is the quest placements Quick Start made counts as unedited: planSeedSync refreshes it to the new layout, and tonight's Quick Start quests are placed again on the new layout with the existing quickStartTemplePlan (same rule as Quick Start itself). Identify Quick Start's placements reliably (a marker on the record or the quest ids Quick Start created — choose the robust one and document it); a Game Master's own room edits (or quest placements made in the Temple Creator / Temple Quests tab) still make the copy 'edited'. Specs: (a) a copy with only Quick Start placements refreshes and gets tonight's quests re-placed on the new layout; (b) a copy with a GM edit stays edited; (c) Quick Start run against the SHIPPED Eagle Wind places tonight's quests only in rooms reachable without a key (first fix quickStartTemplePlan if it picks m006 behind the locked door: Quick Start's rooms must be reachable from the entrance with no key, Bomb or seal).

4. Cheap sweep (same wave)

  • Process wording in source: dressPlans.ts:281 ("The lead's rulings"), dressDoors.ts:5, 128, 253 ("the lead's ruling") -> plain design rationale.
  • dressPlans.ts:113 still says the circle lands "beside the Wind Whistle" (it is 50 gold and a Potion now).
  • tools/art/temple_floors.py:35 says Wind is "made by hand".
  • TempleChestReveal.vue:181 says "Everything starts unticked" (not in whole mode).
  • tests/e2e/specs/classic-hera.spec.js:16 points at the git-ignored task-7-report.md: point it at docs/superpowers/plans/2026-10-19-classic-dungeon-temples-record/ (the archived record) instead.
  • WindTemple.spec test title says "the three cracked walls" (two now).
  • withHandRooms's doc comment sits stacked above handRoomTrouble: move it above withHandRooms.
  • Dead: ClassicPlan.trap (dressPlans.ts:68) is written but never read — remove it or wire it (remove unless a trap room needs it).

Gate

Run every spec you touch, one at a time, plus: RoomInteractions, TempleSolver, quickStartTemple, importAllTemples, ClassicTempleRefresh, wakeOnEntry, WindTemple, ClassicTemples, ClassicDungeonGuards, TempleCreatorRoomContent, TempleSystemCleared. chemx typecheck once at the end (the lead allows it for this final wave). Audit npx --yes [email protected] audit --no-index --unroll > /tmp/audit-final-fix.txt 2>&1 (no file you touch may newly appear under LINE_BUDGET_FILE / CONTROL_FLOW_INLINE_BOOLEAN / TYPE_COLOCATION / HOOK_RETURN_OVERLOAD / UNGUARDED_LOGGING / CONTROL_FLOW_CASCADE_GUARDS), then git checkout -- chemx-ratchet.json.

⚠️ **GitHub.com Fallback** ⚠️