task 7 report - xopherdeep/do-it-for-the-xp GitHub Wiki
Status: DONE_WITH_CONCERNS (the Cypress walk is not green, see "The e2e"; and the dressing deviates from the brief in three places the Tower of Hera's data forced; each is
recorded in classicReport and below).
Commits on feat/classic-temples-2 (only my paths, git add <files>):
c2773bde refactor(tools): the quest plan words and the module renderer leave regenerate.ts, so the dress step can share themf9b5cefa feat(temples): the Storm Temple follows the Tower of Hera, dressed from its JSON-
0a5d0d5d test(e2e): the Storm Temple walked along the solver's run, with a read seam for where the hero stands(the Cypress walk, not green yet, and the__xpTemples.stateread seam it uses)
-
tools/temples/questPlan.ts:Schedule,PlanQuest,SCHEDULES,templateFor, moved out ofregenerate.tsverbatim. -
tools/temples/renderModule.ts:literal,camel,renderModule(id, temple, header: string[]).regenerate.tsrenders throughrenderShippedModule(id, temple)(its old header, built inshippedHeader). The seven regenerated modules are byte-identical: ShippedTemplesAudit's "is exactly what regenerate.ts writes" passed after the move (218 passed) before anything else changed. -
regenerate.tskeepsPLANS,optionsFor,generateShipped,SHIPPED_IDS;storm-templeleftPLANS; the header says where it went.
| Module | Lines | Holds |
|---|---|---|
dress.ts |
170 | entry: dressDungeon(dungeon, plan), dressClassic(id), classicReport(id), renderClassicModule(id, temple), the extras (shop, save, camp, empty), the CLI (esbuild ... --outfile=/tmp/dress-temples.cjs && node /tmp/dress-temples.cjs [id]) |
dressPlans.ts |
58 |
ClassicPlan, CLASSIC_PLANS (Storm), CLASSIC_IDS, loadDungeon(id), DUNGEON_DIR
|
dressBoard.ts |
~370 | the board: cells read as items, one fight per LTTP room, the precedence, moves, growth, the Master Room |
dressDoors.ts |
~225 | the side table into sides, one-ended small locks, the Boss door, Bomb chests, hopsFrom
|
dressChores.ts |
~175 | mini-bosses, must-clear monsters, side rooms, repeats / overflow / left |
dressRooms.ts |
~230 | slots to rooms: tokens, content per kind (a lookup table), stairs and circle targets, locked climbs, the trimmed maze, placements
|
classicReport(id) returns { mustClear, repeats, overflow, left, moves, dropped, merged, bombChests, placements }: a
superset of the brief's { mustClear, repeats } plus the handoff's moves. placements lists every room with its
type, cell, the converted cell it came from, its LTTP room and whether the dressing added it; the specs and the next
seven temples read the dressing through it.
One fight per LTTP room (Review Focus 2). The screen with the most enemies fights (ties: floor order, then reading
order); the other screens' enemies fold into it (merged). The room is must-clear when any of its screens has
shutter or keyDrop and it has enemies; the key drop becomes the fight's drops ({ chest: 'dungeon', dungeon: 'key' | 'master-key' }). A key drop in a room with no enemies lies in the open (key room; a Big Key becomes a Boss
Key chest). GT Quad Pot's rule holds: enemies alone never make a must-clear room.
One thing per cell, by precedence: entrance > boss > must-clear fight > stairs > Big Key chest > Big Chest > other
chests > pot key > puzzle > circle > side fight > hole. Two deviations from the handoff's suggested order, both forced
by Hera (see Concerns): a must-clear fight outranks the stairs sharing its screen (the fight is what gates the doors
there; the flight lands next door through targetCoords), and a hole comes last (a pit replaces its cell's walking
doors, so one on a screen the hero must cross cuts the dungeon in two: with the handoff's order Hera's Startile Corner
became a pit and the tower was unsolvable).
What loses its cell moves to the nearest free converted cell of the same LTTP room, else the nearest free converted cell of the floor, else a wall position inside the grid, else a grown row or column (Manhattan distance, ties by reading order; column before row). A room the dressing adds opens on one neighbour only, its anchor (the nearest to the source cell, a room displaced from the same cell first), so it never shortcuts a lock. Stairs, chests, keys and side fights always move. A displaced hole or circle is kept as a circle only when its landing is a circle (the ride comes back; Hera's fairy room); otherwise it is dropped and listed, as is a displaced riddle. Nothing in the no-drop list (chests, keys, map, compass, Big Key, Big Chest) is ever dropped: the spec counts each against the JSON.
The Master Room goes in a dead-end empty cell beside the boss, else a wall position inside the grid beside it, else
a grown row or column; it opens on the boss only (both ends masterlocked).
Sides (sides, as the Temple Creator draws them): open / shutter / item -> door; small-key -> locked on the end
the hero reaches first (BFS over the JSON, every non-wall side and link open) and door on the far end, so the two
ends never both want a key; big-key -> masterlocked both ends; bomb -> bombable both ends; wall -> wall. Every
way into the boss cell is masterlocked on both ends. A wall the dressing grew a room behind becomes a door to it.
Stairs are stairs-up/stairs-down by floorHeight, with targetLevel and targetCoords pointing at where the
twin flight stands now (following a flight that moved). content.locked comes from ClassicLink.lock
(small-key -> small, big-key -> master), and the flight whose landing was the boss's cell is locked master
(the handoff's Hera/Skull/Ice rule; the boss's displaced landing sits beside him behind the Boss door as well). The
hole-or-teleport-into-the-boss case is not needed by Hera and is left for the temple that needs it. A locked flight
has its own token and its landing is free (every room has its own token).
Circles name their target: the cell their link names when it is a circle, else the circle on that floor that
leads back here, else that floor's first circle. A lone hole is a pit.
Chests: big-key -> master-key; big-chest -> plan.relic; map, compass, small-key -> the item; other -> 25 gold;
a Bomb chest -> { chest: 'consumable', items: ['Bomb'] }. Puzzle -> { puzzleType: plan.puzzle }.
Bomb chests (lead ruling): with every crack read as a wall, each cracked wall the hero stands before and cannot pass gets a Bomb in the nearest empty converted cell in reach before it (a room added beside it if none), those cracks count as open and the walk is tried again until the boss is in reach. Whether or not a shop is reachable.
Chores (lead ruling): the plan lists starters first. A mini-boss is a must-clear room whose door opens straight on
the Boss Key chest or the Big Chest (post-move cells); short of the plan's count, the must-clear rooms nearest the Boss
Key chest, then the Big Chest, are promoted; beyond it, the rest stay must-clear monsters; mini-boss templates go by
path order. The must-clear monster rooms take the plan's first N chores, easiest first in path order (stable); a plan
shorter than N cycles and lists the repeats. Starters beyond N get side rooms nearest the entrance (overflow); other
extras leave (left). Remaining side rooms cycle their floor's must-clear templates (per-floor counter), a floor with
none borrowing the nearest floor's (lower first), a temple with none the plan's first chore (reported as a repeat).
Fight content mirrors the generator's: difficulty: 'easy' | 'normal' by template difficulty, theme: plan.theme,
lockOnEnter on sealed rooms, the boss with element and difficulty: 'boss', the mini-boss hard.
Extras: free converted cells nearest the entrance (path hops, ties by floor order then reading order): one shop
(specialItem: plan.shop), one save, then one camp per floor (healthPoints: 15), the rest empty. Bomb chests take
free cells first.
Trim: trailing empty rows and columns of a floor are cut (the converter sizes a grid to the dungeon's extent). Leading ones cannot be cut without moving every cell, so Hera's 3F keeps its 17 rows (see Concerns).
6 floors (B1, 1F, 2F, 3F, 4F, 5F), 31 rooms, entrance [1, 1, 0] (1F), 2 must-clear rooms, 1 mini-boss, 0 Bomb chests,
size 22 (>= 21). Plan: mustClear bed-basilisk 1 daily am, shoe-shrew 1 daily, toybox-troll 2 daily, mess-hog 2 daily,
piece-poltergeist 2 weekly (today's beasts, starters first); mini-boss under-bed-bogey 5 weekly; boss clutter-chimera
8 weekly; relic Lightning Rod; no shop; trap and puzzle as today (unused: Hera has no trap cell and both riddles were
displaced).
Rooms: B1 Tile Room = stairs up (the locked flight's free landing), Tridorm = mini-boss (its south door opens on
the Boss Key vault), Basement Cage = stairs up, Torches = Boss Key chest; 1F Hera Back (0,0) = stairs down locked
small, (0,1) = map chest, Lobby = entrance, Up Stairs Landing = stairs up; 2F Startile Wide (0,0) = side fight, (0,1) =
stairs up, Corner = must-clear shoe-shrew, Beetles = must-clear bed-basilisk (nearest the entrance, easiest first
is a tie); 3F (0,0)/(0,1) stairs, (1,0) side fight, (1,1) Lightning Rod, Fairies = circle; 4F (0,0) stairs down, (0,1)
stairs up locked master, (1,0) circle to the fairies, (1,1) side fight; 5F boss, landing, Master Room.
Moves (11): small-key chest B1 (1,0)->(2,0) added; side fight B1 (1,0)->(2,1) added; side fight B1 (1,1)->(1,2) added; map chest 1F (0,0)->(0,1); side fight 1F (0,0)->(0,2) added; stairs 1F (1,0)->(1,2) added (the lobby's flight to the cage); stairs 2F (1,1)->(1,2) added (Beetles' landing from 1F); big-chest 3F (0,0)->(1,1); compass chest 3F (0,1)->(2,1) added (a wall position inside the 17-row grid); teleport (the hole into the fairy room) 4F (0,1)->(1,0); stairs 5F (0,0)->(0,1) added (the boss's landing, behind the Boss door).
Dropped (10): the riddles of the Tile Room and Torches (displaced by stairs / the Boss Key chest); the star-tile holes of 2F (0,0), (1,0), (1,1), the holes of 3F (0,0), 4F (0,0) and the boss cell, the warps of 3F (0,0) and the boss cell: each lands on a cell that is no circle. Merged (8): the lesser screens of Hera Back, Startile Wide, Hera 4F, Hera 5F.
Overrides: overflow: ['toybox-troll'] (the third starter has a side room at 1F (0,2), the first side room past the
map); left: ['mess-hog', 'piece-poltergeist']; repeats: []. Side rooms repeat bed-basilisk (B1 (2,1), 2F (0,0),
3F (1,0), 4F (1,1)) and shoe-shrew (B1 (1,2)); the boss's element is storm.
Solver notes accepted: four R8 twin notes for the two relocated flights (each end of 1F (1,1)<->2F (1,2) and
1F (1,2)<->B1 (1,0)); solvable holds, every room is in reach, the audit passes, and with the Boss Key chest turned
to gold the solver is stuck on "the master key is out of reach".
importAllTemples.ts: a refresh first starts every hero's run in that temple over (startRunsOver): a run the
engine still holds is dropped (forgetTempleRun, so neither refreshRun nor a queued save carries it over), and every
saved record is rewritten with progressForNewLayout (new in templeReset.ts, with entranceOf): the new entrance,
no keys, Boss Key, map or compass, nothing visited, won, opened or emptied; keyItems (the Pegasus), the cleared badge,
timesCleared, bloodMoons and a scheduled moon stay. TempleProgressDb.getProgressForTemple(templeId) is new. A
failure is warned about and never blocks the layout write. importAllTemples.spec's "never touches hero progress" is
reworded to what is now true (it still passes: its fake progress store is not the app's).
tests/e2e/specs/classic-hera.spec.js seeds the battle fixture, signs hero-1 in, opens /temple/storm-temple/hero-1
and walks the solver's critical path with the arrow controls: east to the lobby's relocated flight, down to the cage,
the small key chest, back up and north to the locked flight ("Unlock and climb", the key count goes 1 -> 0), the Tridorm
(won through the Battle Field: Tackle each chore of the Under-Bed Bogey's checklist), the Boss Key chest, back up, the
stairs to 2F (the floor-wake prompt's Onward when it shows), Bed Basilisk and Shoe Shrew (both sealed, both won),
through the side room to 3F and 4F, "Unlock and climb" with the Boss Key, the Boss door (door-unlock), Clutter Chimera,
then the Master Room, where it asserts the Pegasus chest opens ([data-cy=pegasus-reveal]). It reads where the hero
stands through a small dev-only seam added beside __xpTemples.save: __xpTemples.state(templeId) (the route only names
a cell when a battle hands the hero back). It walks the critical path, not every room of order (the fairy room, the
compass nook and the three dead-end side rooms are off it).
Cypress result: NOT PASSING (the lead stopped the iterations at five). Run against the worktree's own server
(pnpm vue-serve --port 8103 --host 127.0.0.1, stopped afterwards; the shared 8100 untouched) with
pnpm vue-cli-service test:e2e --headless --browser chrome --url http://localhost:8103 --spec tests/e2e/specs/classic-hera.spec.js.
What each run taught (screenshots 01-05 in tests/e2e/screenshots/classic-hera.spec.js/ are from the farthest run):
- The arrows, the climbs, the locked flight and the seam all work; a chest room has no choice sheet (a tap brings the chest reveal up itself). Fixed.
- The chest's Take wants its loot rows ticked first. Fixed.
- Test 1 passed (the small key, the locked flight, the key count 1 -> 0). Test 2's fight: a dormant mini-boss plays as a classic fight with the temple's own beast (the Storm Drake, one task), not the template's Under-Bed Bogey, so the enemy-name and checklist assertions were wrong. Fixed with a generic fight loop (Tackle the first chore not done until the victory card).
-
Farthest run: test 1 passed; test 2 beat the Tridorm, took the Boss Key (shots 04, 05) and failed at the climb
back: after a battle hands the hero back, an earlier copy of the temple page lingers hidden
(
.ion-page-hidden) and the sheet selectors matched that copy (<div.choice-reveal.kind-sheet>under a page withdisplay: none). Fix: scope the sheet and the room controls to the shown page. - Scoping every selector to the page broke test 1 at the first chest: the chest reveal (and the door and Pegasus reveals) render outside the page element. The committed spec scopes the sheet and the room controls (run 4's need) and leaves the three reveals unscoped (runs 3 and 4 proved them); that exact state has not been run (no sixth iteration, per the lead). Tests 3 and 4 never ran past their first step in any run (they start where test 2 ended).
Still open for whoever picks it up: run the committed state; if the lingering page also carries a hidden chest reveal,
scope those three reveals to the page's own sibling (the reveal is a teleported overlay: find its mount point) or match
on :visible; then the Boss door step (door-unlock, the hero may or may not step through on done) and the
Pegasus assertion are untested in the browser.
RED (before any implementation; the three new specs all failed to compile on the missing modules, then the refresh spec
failed on behaviour once dressPlans.ts existed):
chemx test tests/unit/ClassicTemples.spec.ts
✖ Test suite failed to run TS2307: Cannot find module '../../tools/temples/classic/dress'
chemx test tests/unit/ClassicDress.spec.ts
✖ Test suite failed to run (import { dressDungeon } from "../../tools/temples/classic/dress")
chemx test tests/unit/ClassicTempleRefresh.spec.ts
✖ Test Failures (3 failed out of 4)
puts the hero on the new entrance with no keys ...: expected currentLevel "1F" ... (the old run was kept)
starts every other hero's run in that temple over too: ... (kept)
drops a run the engine still holds in memory ...: expected undefined, received {"currentLevel": "2F", "currentPosition": [3, 4], "playerKeys": 1, "hasMasterKey": true, ...}
Step 3 (the move, byte-identical): chemx test tests/unit/ShippedTemplesAudit.spec.ts -> All tests passed (218 passed).
GREEN (final):
chemx test tests/unit/ClassicDress.spec.ts All tests passed (24 passed)
chemx test tests/unit/ClassicTemples.spec.ts All tests passed (20 passed)
chemx test tests/unit/ClassicTempleRefresh.spec.ts All tests passed (4 passed)
chemx test tests/unit/ShippedTemplesAudit.spec.ts All tests passed (215 passed) # 218 before: the classic block merged three small tests
chemx test tests/unit/ClassicDungeonJson.spec.ts All tests passed (106 passed)
chemx test tests/unit/importAllTemples.spec.ts All tests passed (24 passed) # its subject changed, so I ran it
Two implementation bugs the specs caught on the way: the handoff's hole-above-fight precedence made Hera unsolvable (ClassicTemples: solver + reachability), and the anchor tie-break's sign was flipped (the Cage's beasts hung off the Boss Key vault instead of behind the Cage's key chest; now pinned in the Storm block).
Tests written: ClassicTemples.spec.ts (the brief's Step 1 list over CLASSIC_IDS, plus the Storm pins);
ClassicDress.spec.ts (the rules on five hand-made dungeons in classicFixtures.ts: doors, a key drop, a pot key, the
mini-boss before the Boss Key, a displaced Boss Key chest, chores dealt and repeated, extra mini-bosses, trim and
growth, the Bomb chest on the only way, a lone hole, a circle from a hole, a dropped riddle, the boss reached by stairs,
the extras and borrowed beasts); ClassicTempleRefresh.spec.ts (Review Focus 1, with stormBeforeHera, the old
layout verbatim); ShippedTemplesAudit's split (seven regenerated, a classic block, sizes and counts from the dressed
rooms, "once" per sealed room, deduped starter fill).
npx --yes [email protected] audit --no-index --unroll > /tmp/audit-t7.txt, run three times (after the first
implementation, after the fixes, after the seam). First run named my files under CONTROL_FLOW_INLINE_BOOLEAN (4 sites)
and CONTROL_FLOW_DISPATCH_SWITCH (3 switches, 39 against the ratchet's 36) and one CRITICAL nested ternary: all fixed
(named conditions, lookup tables, early returns). Final run: none of my files under LINE_BUDGET_FILE,
CONTROL_FLOW_INLINE_BOOLEAN or TYPE_COLOCATION; DISPATCH_SWITCH back at 36; no CRITICAL. The only mention left is
UNGUARDED_LOGGING for the CLI's console.log lines in dress.ts (the same lines regenerate.ts has always had).
chemx-ratchet.json restored with git checkout -- chemx-ratchet.json after each run; never committed.
Created: tools/temples/questPlan.ts, tools/temples/renderModule.ts, tools/temples/classic/dress.ts,
dressBoard.ts, dressChores.ts, dressDoors.ts, dressPlans.ts, dressRooms.ts, tests/unit/ClassicTemples.spec.ts,
tests/unit/ClassicDress.spec.ts, tests/unit/ClassicTempleRefresh.spec.ts, tests/unit/classicFixtures.ts,
tests/e2e/specs/classic-hera.spec.js.
Modified: tools/temples/regenerate.ts, src/lib/engine/temples/storm-temple.ts (generated),
src/lib/engine/core/dungeons/importAllTemples.ts, templeReset.ts, templeFreshness.ts (the state seam),
src/lib/databases/TempleProgressDb.ts, tests/unit/ShippedTemplesAudit.spec.ts (499 lines), tests/unit/importAllTemples.spec.ts.
Every file I created or grew is under 500 lines. Not run (per the rules): typecheck, lint, verify, build.
-
Starter overflow (lead ruling vs Hera). The ruling wants every starter beast of today's plan in a must-clear room;
Hera has two must-clear rooms and today's Storm plan holds three starters. Smallest deviation: Toybox Troll keeps a
side room of its own, nearest the entrance, so
quest-toysstill fills a room (classicReport.overflow); the side room is unsealed, as side rooms are. The alternative (dropping the third starter) loses a starter fill. -
Precedence differs from the handoff's parenthetical in two places (must-clear fight above stairs; hole last),
forced by solvability and the shutter gating; recorded above. A relocated flight leaves R8's twin note in the solver's
reasons(solvableis untouched; play and the solver followtargetCoords); the classic specs accept exactly that note and nothing else. -
Size. With two must-clear rooms the Storm Temple reaches 22 only because side rooms (repeats) count toward
templeSize, as the audit spec's size check reads them; the distinct chores add up to 15. - Hera 3F stays 17 rows (the fairy room sits at row 16): the brief's trim applies to trailing rows only, since cutting leading rows would move every cell. The map shows 14 empty rows between the compass nook and the fairy room.
-
No shop, save or camp in Storm: the tower has no empty converted cell. The plan's
trapis unused by the dressing (no converted cell is a trap); kept in the interface as the brief names it. -
Big-key doors between two ordinary rooms (Hera's Startile Corner/Wide) are written
masterlockedas the table says, but the engine's Boss door rule applies only to doors into a boss room, so in play and in the solver they are plain doors (the Boss Key still gates the boss through the locked climb and the Boss door). -
The CLI's unhandled rejection guard:
dressChoresreadsSTARTER_QUESTS, which pulls the app's browser stores along; under node their init rejects after the modules load. The CLI block swallows exactly that message and rethrows anything else. A leaner starter list would remove it. - The hole/teleport-into-the-boss gate (Skull, Ice) is not implemented; the stairs case is, with a test (DROP fixture).
-
ClassicTemples.speccompares the module on disk withrenderClassicModule(id, dressClassic(id)); any change to the dressing needs the CLI run again (as withregenerate.ts).
Status: DONE_WITH_CONCERNS (every item of the list done; the e2e's one attempt got two of four tests green and is
skipped with a STATUS note, as ruled). Commits on feat/classic-temples-2, tree clean:
b8577b6c feat(temples): a pit can name where it drops, and a flight that names its landing is paired there760f7812 fix(temples): the dress step keeps every hole, gates a fall onto the boss, and compacts far-off island cells8d007bdc fix(temples): opening a temple waits for the shipped temples' seed sync, and the sync's header says what it does to runsd5ae254a test(e2e): the Storm Temple walk reaches the star-tile rooms, and is skipped until it is green
- Engine:
hazards.ts(pitFloor,fallInPit(room, ctx)) readscontent.targetLevel(any lower floor) andtargetCoords({x: col, y: row}) and lands there first; a pit that names none drops as before (the next floor down, the same cell, else the first stairs up).onEnterRoom's "floor below" check uses the same. - Solver:
templeGraph.linkPitsreads the same fields; the R8 note names the cell the pit named when it is a wall. - Dress: every hole becomes a pit with the target of its JSON link (
dropTarget); a displaced hole is never dropped (relocated to the nearest free cell, added beside its source when none;movessays so); no hole becomes a circle any more. A circle whose landing is no circle (Hera's fairy room warps onto a stairs cell) gets a circle added beside its landing, pointed back (placeLandingCircles), so no circle fizzles and no island is a trap. - Two deviations recorded: the boss room's own exits are settled last (its hole is a pit beside his landing, never touching the boss cell, which would be a second door into his room; its warp keeps the displaced-circle rule and is dropped when its landing is no circle); a displaced circle still follows the old rule (kept only when it lands on a circle), the fix list ruling on holes only.
- Specs: RoomInteractions.spec ("names its landing", "a one-room floor"), TempleSolver.spec ("R8 Pits: ... any lower floor"), ClassicDress.spec (DROP: the lone hole's target, the moved hole, the landing circle), ClassicTemples.spec ("drops through every hole of its dungeon exactly once, where the dungeon says").
dressLinks.placeAntechamber: when any hole or circle lands on the boss's cell, an added circle beside the boss (the
Boss door between, both ends masterlocked) takes the landing, paired with a circle added beside the entrance (the
way back out once the boss is beaten, which R2 wants). Pits and circles that named the boss land in it. Spec: the FALL
fixture (ClassicDress.spec "a boss reached by a fall alone"): solvable with the Boss Key, "the master key is out of
reach" without it; ClassicTemples.spec checks a fall onto the boss lands beside him behind a masterlocked side.
Run against the worktree's server on 8103 (stopped afterwards): 2 passing, 2 failing (e2e-hera-6.log). Passed:
test 1 (the small key, the key count 1 -> 0, the locked flight) and test 2 (the Tridorm won through the Battle Field,
the Boss Key chest). Test 3 beat the Bed Basilisk and the Shoe Shrew (screenshot: "Shoe Shrew was defeated", a level
up) and failed leaving the Shoe Shrew's victory card: the hero levelled up, the card was still counting when the spec
tapped it, and the Battle Field stayed up past the 30 s timeout (expected '/battle/hero-1/temple/storm-temple/2F/0/1' to equal '/temple/storm-temple/hero-1/0/1'). Test 4 cascades (never ran past its first step). As ruled: the describe
is describe.skip with a STATUS note; leaveVictory (tap the card until the temple is back) is written in but unrun.
Screenshots 01-06 in tests/e2e/screenshots/classic-hera.spec.js/. The three reveals read their visible copy
([data-cy=chest-reveal]:visible ...), the sheet and room controls the shown page.
- Big-Key doors between ordinary rooms: drawn
door(the boss's own doors staymasterlocked), listed inclassicReport(id).plainBigKeyDoors(Hera: 2F (0,0) south, Startile Wide to the Corner). Specs in both classic specs. - Many-screen must-clear rooms: a flight displaced from a must-clear fight skips every cell of that LTTP room
(
PlacementLimits.avoidRoom); the TWO SCREENS fixture lands it beside the fight. ClassicTemples.spec checks that blocking the fight screen blocks the room as a passage (the outside reach is the same as with the whole room blocked). - Sparse floors:
compactIslandsmoves an island (walls on every side) that lies outside the ring around the other cells' bounding box to the nearest free position on that ring, before anything is read;classicReport(id).compactedlists it and every link follows (board.converted). Hera's 3F is 4 rows (the fairy room at (2,0)), not 17. - R8: the engine pairs a flight with the stairs its
targetCoordsname (no note); ClassicTemples.spec asserts every flight's landing is a stairs room of the opposite kind andsolveTemple(...).reasonsis[](no filter). This also fixed TempleSolver.spec's R12 block, which the Storm module had been failing since f9b5cefa (not in round one's gate). - Bomb chests: only a crack whose closing alone cuts the boss off earns one (two side by side: the nearest does); the
chest's cell is reached from the entrance over unlocked doors (
hopsFrom(graph, start, passable)), nearest the wall's near end, else a room added beside it. CRACK fixture: a dead-end crack gets none; CRACK locked: the yard before the small lock gets it, not the nearer anteroom. - No empty cell: one shop added beside the entrance (Hera: 1F (2,0)), no save or camp. CORRIDOR, TOWER, FALL, Storm.
- ShippedTemplesAudit.spec: 458 lines; the regenerated count is
SHIPPED_IDS; the classic block moved into ClassicTemples.spec (400 lines) as one test. - importAllTemples.ts's header says the one case it touches progress; the fake progress test is gone from importAllTemples.spec (it kept a temple-store-only check); ClassicTempleRefresh.spec gained the real one: a current or an edited layout leaves every run alone.
- First launch:
useTemple.openTempleawaitsensureBuiltInTemples()beforeensureTempleFresh; newtests/unit/TempleOpenOrder.spec.tsholds the sync and shows the record is not read until it settles.
6 floors, 39 rooms (was 31), 2 must-clear, 19 moves, 4 dropped (the two riddles, the two warps of 3F (0,0) and the
boss cell), 0 Bomb chests, size 22; compacted 3F (16,0) -> (2,0); pits at 2F (0,2), (1,2), (2,0), 3F (2,1), 4F (1,0),
(0,2), 5F (1,1), each with its target; the fairy room's circle at 3F (2,0) rides to an added circle at 4F (1,2); the
shop at 1F (2,0); the compass at 3F (3,0). Every rule of ClassicTemples.spec holds (25 tests); the Storm pins are
updated. The e2e walk's 2F landing is now (2,1), under the Beetles room.
chemx test tests/unit/RoomInteractions.spec.ts All tests passed (148 passed)
chemx test tests/unit/TempleSolver.spec.ts All tests passed (53 passed, 1 skipped) # the pre-existing it.skip
chemx test tests/unit/ClassicDress.spec.ts All tests passed (31 passed)
chemx test tests/unit/ClassicTemples.spec.ts All tests passed (25 passed)
chemx test tests/unit/ClassicTempleRefresh.spec.ts All tests passed (5 passed)
chemx test tests/unit/importAllTemples.spec.ts All tests passed (24 passed)
chemx test tests/unit/ShippedTemplesAudit.spec.ts All tests passed (210 passed)
chemx test tests/unit/ClassicDungeonJson.spec.ts All tests passed (106 passed)
chemx test tests/unit/TempleOpenOrder.spec.ts All tests passed (1 passed)
RED first each time: the two engine specs failed on the untargeted fall / the unnamed pit door; the dress specs failed
to compile on compacted / plainBigKeyDoors; the open-order spec was written against the new behaviour.
Audit (npx --yes [email protected] audit --no-index --unroll > /tmp/audit-t7f.txt, three runs, ratchet restored
after each): none of my files under LINE_BUDGET_FILE, CONTROL_FLOW_INLINE_BOOLEAN, TYPE_COLOCATION or
HOOK_RETURN_OVERLOAD; the counts match the ratchet (LINE_BUDGET 36/4, INLINE_BOOLEAN 5/4, HOOK_RETURN_OVERLOAD 19,
DISPATCH_SWITCH 36, CASCADE_GUARDS 14, after one nested ternary and one guard cascade of mine were fixed on the way);
only the CLI console.log lines of dress.ts and regenerate.ts remain (UNGUARDED_LOGGING, as before).
- The e2e is skipped, two of four tests short (above); the remaining walk (3F, 4F, the Boss Key climb, the Boss door, the Pegasus) is untested in the browser.
- The boss room's own exit links and displaced circles follow my rules above, not the fix list's (which rules on holes).
- A fall-only boss floor gets two added circles (the antechamber, the way back beside the entrance): Earth and Ice will show that shape; the circle beside the entrance takes the nearest free cell, grown when none.
-
dressBoard.tsimportsdressLinks.tsand back (functions only, called after both load); fine for jest and esbuild, worth knowing.
Status: DONE_WITH_CONCERNS (every item done; the e2e stays skipped as ruled in round 1; two design concerns below).
Commits on feat/classic-temples-2, tree clean:
dfdede88 test(temples): TempleSystemCleared's seed-sync mock answers ensureBuiltInTemples, which openTemple now awaitsc9d25086 fix(temples): the dress step keeps every circle, lands falls in dead ends, rides back beside the fall, and dresses Earth and Ice
TempleSystemCleared.spec's mock of importAllTemples answers ensureBuiltInTemples (resolving). Run one at a time,
all green: TempleSystemCleared 31, TempleSystemFloors 20, DragonEggRoom 50, FightDrops 42, TempleChestTake 21,
TempleKeyCount 7, BossKeyChest 19, TempleMoveIcons 6, TempleProgress 34 (the one more spec chemx q/grep found that
imports useTemple), TempleOpenOrder 1. The specs without a mock run the real sync on their in-memory storage: it
creates the nine records and touches no run (only a refresh does), so nothing broke.
dressLinks.placeAntechamber pairs the antechamber's circle with one added beside the room the hero fell from
(fallSource): the cell the hole was converted in when the pit was pushed out of it (that cell holds what stayed, the
Ice Palace's Antechamber fight), else the converted neighbour the hole's cell opens on (Skull Woods' Spike Corner
before the Final Drop), else, for a hole in an island, the entrance. Specs: FALL (the circle back lands under the
vault, the room before the drop; the shortest route to the Boss door is four doors, the same as through the hole);
the in-memory Earth and Ice (the ride back lands within two cells of the fall's source, floor shift and compaction
applied).
placeInDeadEnd: a free dead-end cell (one non-wall side) of the hole's own LTTP room, else a room added beside its
source (tryOpenBeside with addedOnly, so a neighbouring room's dead end is never taken), else the nearest added
room; placeNearest gained addedOnly. Holes are settled before every other displaced thing, so a pit gets a room's
one dead end before a circle or a chest. Specs: CROSSROADS (the pit takes the room's east dead end, never the passage
between), DROP and ClassicTemples ("no pit cell has more than one open side unless it is the hole's own cell"). Ice's
B1 is whole again (R1 gone).
- Displaced circles are relocated like holes and never dropped;
placeLandingCirclespairs a circle whose landing is no circle with the circle on that floor that leads back to it, else adds one beside the landing.report.droppednow holds riddles only (Storm: two). -
openNear(tryOpenBeside, else the nearest added room) replaces every throwingopenBeside: the Master Room, the antechamber, landing circles, the shop. - The Bomb chest with no reachable empty cell before the crack is added beside the first reachable room on the entrance side (the wall's near end first) that has a free side, else the nearest added room; the addition is a recorded move. Earth no longer throws (its chest sits at 1F (2,5)).
-
shiftFloors(aftercompactIslands): a floor whose cells all start past the first row or column moves up and left;report.shiftedlists the shift per floor andnowAtin the specs applies it. Ice's B6 is 5x3, not 17x3. (trimmedkeeps cutting trailing rows and columns; the leading ones are cut on the board, before any link is read.) - Acceptance: ClassicTemples.spec "the next temples, dressed in memory" dresses earth-temple and ice-temple under the
Storm plan as a stand-in (no module written): both build,
solveTemple(...).solvable, no R1, the audit passes, the Boss Key is needed, and the ride back from the boss lands beside the fall's source. Ice still carries an R4 note (its Boss Key chest is reachable without passing a mini-boss): a plan matter for Task 8 (which must-clear room becomes the mini-boss), not a reachability one.
43 rooms (was 39): Hera's two warps are kept as circles (the Big Chest screen's at 3F (3,0), riding to a circle
added beside the locked flight on 1F (2,0); the boss's at 5F (1,1), riding to one beside the 3F stairs at (0,2)),
the holes pushed out of their screens sit in dead ends (2F (0,2), (1,2), (2,0); 3F (2,1); 4F (0,2), (1,2); 5F (0,2)),
the compass at 3F (3,1), and the one empty converted screen left (4F (1,0), whose beasts merged into the room's fight)
is the shop, so none is added beside the lobby. Dropped: the two riddles. plainBigKeyDoors unchanged.
chemx test tests/unit/ClassicDress.spec.ts All tests passed (35 passed)
chemx test tests/unit/ClassicTemples.spec.ts All tests passed (32 passed)
chemx test tests/unit/ClassicTempleRefresh.spec.ts All tests passed (5 passed)
chemx test tests/unit/ShippedTemplesAudit.spec.ts All tests passed (210 passed)
chemx test tests/unit/TempleSolver.spec.ts All tests passed (53 passed, 1 skipped)
chemx test tests/unit/RoomInteractions.spec.ts All tests passed (148 passed)
+ the ten useTemple specs above
RED first: the CROSSROADS, FALL way-back and in-memory Earth/Ice tests failed on the old tool (the circle beside the entrance, the pit on the passage, Earth's throw); the mock fix turned TempleSystemCleared from 9 failures to green.
Audit (npx --yes [email protected] audit --no-index --unroll > /tmp/audit-t7f2.txt, ratchet restored): none of my
files under LINE_BUDGET_FILE, CONTROL_FLOW_INLINE_BOOLEAN, TYPE_COLOCATION or HOOK_RETURN_OVERLOAD; every count as
the ratchet (CASCADE_GUARDS 14, INLINE_BOOLEAN 5/4, LINE_BUDGET 36/4, DISPATCH_SWITCH 36, HOOK_RETURN_OVERLOAD 19), no
CRITICAL; only the CLI console.log lines and useTemple.ts's pre-existing entries.
- Circles are two-way in the engine while LTTP's warp tiles are one-way. Keeping Hera's two displaced warps (the ruling) gives a two-way pair between a circle beside the lobby's locked flight and the Big Chest screen's circle on 3F; from there the fairy circle rides to 4F. The Boss Key still gates the boss, but a hero who finds the ride can skip 2F's two sealed star-tile chores. Options: make a relocated warp whose JSON landing is no circle one-way (an engine flag), or let a plan drop it; the lead decides.
- The shop follows "the nearest empty cell" and so sits on 4F for Storm; the added-beside-the-lobby shop only applies when no empty cell exists. If a shop near the entrance is wanted regardless, that is a one-line rule change.
- Ice's R4 note (above) is for Task 8's plan.
- The e2e remains skipped (round 1's STATUS); the walk's 2F landing and the new rooms do not change its first three tests' path.
Status: DONE_WITH_CONCERNS (every item done; the e2e stays skipped as ruled in round 1). Commit on
feat/classic-temples-2, tree clean:
b48bcaf1 fix(temples): the dress step drops a warp whose ride back skips a seal, locks shifted floors on the right end, and keeps every pit out of passages
dressDoors.demoteShortcutWarps, run right after the board is built: for each warp that got a landing circle added
(board.warpPairs, recorded by placeLandingCircles), the must-clear rooms that block the boss are computed twice on
the solver's graph, with the ride back cut (its door removed) and with it open; a room that blocks only with the ride
cut means the ride goes around a seal, so both ends become empty rooms (kept: Storm's compass hangs off 3F (3,0)) and
the warp is listed in dropped ("its ride back from ... opens a way around a must-clear room"). Pairs are judged one at
a time in the order they were added. Storm: the Big Chest screen's warp is dropped (its ride from beside the lobby
skipped the two star-tile seals); the boss's warp (3F (0,2) to 5F (1,1)) and the fairy room's pair stay. Spec, for
every dressed temple: a sealed room that blocks the boss when the converted one-way warps take no ride back still
blocks the boss in the dressed temple (ClassicTemples "keeps every must-clear room that blocks the boss when warps ride
one way").
smallLockEnd looks the two ends up by the converted cells' own row and column (slot.cell), which the entrance-hop
map is keyed by, not by slot.at (moved by shiftFloors). SHIFTED fixture (cells on rows 2-3): the floor moves up two
rows, the lock sits on the pots' east side, the guard's west side is a plain door, solvable with no reason.
PlacementLimits.besideFirst: a flight displaced from a must-clear fight is added beside its source
(tryOpenBeside with addedOnly), else the nearest added room, never a converted cell (Shadow's flight at 1F (6,1) no
longer lands at (7,4) behind two cracked walls: Shadow solves again). TWO SCREENS gained an empty closet beyond the
seal, the nearest free cell of the floor, which the flight must not take.
- A hole in a passage (its own cell has two or more open sides) is displaced to a dead end added beside it and the passage stays an empty room (PASSAGE fixture; Moon's GT 5F (2,1) no longer cuts eight rooms off: Moon solves). ClassicTemples now asserts no pit of any dressed temple has more than one open side.
- The shop (
placeShop): on the entrance floor, in the empty converted cell nearest the entrance that is reached with the sealed fights and the boss blocked; with none, a room added beside the entrance. Storm's shop sits beside the lobby at 1F (2,1); the save takes 4F's empty screen. -
addBombChestNeartries one room at a time and stops at the first free side. - Comments: dressBoard.ts's header (what moves where), dress.ts's shop rule,
openNear's doc (why it never fails). - Guard spec: "every classic JSON, dressed in memory under the stand-in plan" pins, per temple,
solvable, the solver's exact reasons and the audit's missing names as the tool makes them today: Earth and Light clean; Shadow, Ice, Fire and Moon solvable with one R4 note each (the mini-boss their plans will choose); Water stuck on the locked flight at 1F (0,8) with no key placed by the stand-in plan (R2) plus R4; Wind (the Eagle) with no Boss Key chest (the audit's "Boss Key", R2, R4). Task 8 flips each line as it dresses that temple; a tool regression turns it red.
44 rooms: the two warps' rooms stay (1F (2,0) and 3F (3,0) empty, the compass off the latter), the boss's warp pair
and the fairy pair kept, the shop at 1F (2,1), the save at 4F (1,0); dropped: the two riddles and the 3F warp;
plainBigKeyDoors unchanged. The e2e's first three tests walk the same cells as before.
chemx test tests/unit/ClassicDress.spec.ts All tests passed (37 passed)
chemx test tests/unit/ClassicTemples.spec.ts All tests passed (41 passed)
chemx test tests/unit/ClassicTempleRefresh.spec.ts All tests passed (5 passed)
chemx test tests/unit/ShippedTemplesAudit.spec.ts All tests passed (210 passed)
chemx test tests/unit/TempleSolver.spec.ts All tests passed (53 passed, 1 skipped)
RED first: the SHIFTED, PASSAGE and closet tests and the one-way pin failed on the round-2 tool (36 of 37 in the dress spec, then the Storm pins); the nine-temple guard was pinned from the tool's output after the fixes.
Audit (npx --yes [email protected] audit --no-index --unroll > /tmp/audit-t7f3.txt, ratchet restored): none of my
files under LINE_BUDGET_FILE, CONTROL_FLOW_INLINE_BOOLEAN, TYPE_COLOCATION or HOOK_RETURN_OVERLOAD; every count as
the ratchet (CASCADE_GUARDS 14, INLINE_BOOLEAN 5/4, LINE_BUDGET 36/4, DISPATCH_SWITCH 36, HOOK_RETURN_OVERLOAD 19), no
CRITICAL; dressBoard.ts at 492 lines.
- The warp judgement is greedy, pair by pair in the order added; a dungeon where two warps only together open a way around a seal would keep both. None of the nine does today (the guard spec would show it as a lost seal only through the one-way pin, which runs on every dressed temple).
- A demoted warp that was a lone circle in an island would leave the island with no way out; no dungeon has one (the fairy rooms' pairs are kept), and the one-way pin plus the solver would say so.
- The e2e remains skipped (round 1's STATUS).
Status: DONE_WITH_CONCERNS (every item done; all nine JSONs keep every boss-blocking seal with no exception; the
concerns are judgment calls the data forced, listed at the end). Fresh implementer. Commit on feat/classic-temples-2
(only my paths), tree clean:
adee573d fix(temples): the dress step keeps every seal of its dungeon: what a sealed fight held waits behind it, warps land in front of it, keys stay before their locks
dressBoard.ts (492 lines) lost its placement code to two new modules; every file is under 400 lines:
dressBoard.ts 351 (reading the cells, the settling order, the Master Room, buildBoard), dressPlace.ts 356 (where
a displaced thing goes, the rooms the dressing adds), dressReach.ts 103 (the converted dungeon's walk without one
cell: convertedHops, moved out of dressDoors; the board's walk with nothing in hand: walkFrom; isSeal, isPit,
isLandedOn, walksThrough). ClassicTemples.spec.ts was 525 lines: its two in-memory blocks (the nine-JSON pin and
"the next temples") moved to the new tests/unit/ClassicDungeonGuards.spec.ts (382) with the new guards; it is 456.
- Settling order (
settleRank): what a sealed fight's cell held goes first, its flight before the rest, then holes, then everything else. Moon's 5F Frozen Over flight now takes 5F (1,0) beside the fight (the hole moved off the Moldorm ledge passage used to take it). -
placeBeyondSeal: beside the fight (a nook that opens on it alone, a wall position, a grown row or column), else beside a room the hero walks to only through the fight and no other seal (converted cells the converted dungeon reaches only through the fight, and rooms added off them; never a room a link brings the hero into from in front), else a row or column grown before the first when the fight is on the top or left edge, else (a chest or a key) the fight hands it out itself once won, else beside a room beyond a further fight (walked to from the fight with nothing in hand, so nothing waits on itself), else it throws. Never "the nearest added room anywhere". - A flight or a circle whose other end the hero reaches without the fight (in LTTP it landed the hero inside the
fight) stands beside the fight or in front of it (
openInFront, item 3's rule), never beyond: placed beyond, its twin would bring the hero past the seal. - A boxed-in fight's drops:
Item.holds; dressRooms'dropsOfwrites one Dungeon Item, further small keys as"key"rows and the gold summed (chestLootand the grants read all three). Used by Ice B2 (1,2) Ice Right H (map + pot key:{ chest: "dungeon", dungeon: "map", items: ["key"] }) and Moon B1 Bob's Torch (its small-key chest). - Growth before the first row or column (
growBefore): every room of the floor moves down or right in place (anchors, targets and moves follow); the report'sshiftedtakes it as a negative shift. Only a last resort (Storm and every fixture are untouched by it); used by Moon B1 (a column: GT DMs Room's gold chest), Fire 1F and Shadow B1/1F. - DROP's assertion is strict again: the flight takes the nook that opens on the fight alone (2F (0,3),
grown: false), 3F's landing names{ x: 3, y: 0 }. The dressBoard.ts header is rewritten to match.
On the converted JSON's own graph (every side but a wall open, stairs both ways, holes and warps one way from their own cell; locks ignored), every must-clear fight (the screen with the most enemies of a room that shuts or drops a key) that blocks the boss must still block him in the dressed temple (dressed graph, every door open). Known exceptions: none. Boss-blocking seals kept / lost: Storm 2/0, Earth 4/0 (was 3/1), Ice 4/0, Wind 2/0, Fire 0/0, Light 2/0, Moon 15/0 (was 14/1), Shadow 0/0, Water 1/0.
Further guards, all nine: what leaves a sealed fight's cell is reached on foot only through it (or stands in front of it when its link brings the hero in, or is the fight's own drop); a landing circle for a warp onto a sealed fight opens on the fight or on rooms of its entry side; a key, Big Key, map, compass or Big Chest that moved is reached from its cell with nothing in hand; the shop is on the entrance floor before any key, Bomb or seal; every move lands on what it moved; every chest and key of the JSON is handed out exactly once (drops included); and the solver/audit pins.
placeLandingCircles now opens a landing with openInFront: beside the landing, else beside a room walked to from it
with nothing in hand and no seal passed, on the entry side of a sealed fight (never beyond it). Earth: the West Lobby
warp's landing circle is 1F (2,1), opening on the Back Drop screen west of the fight; the fight's own circle (1,2)
hangs beyond the Big Key mini-boss (via (2,2)-(3,2)); the third section's warp back to the entrance is dropped (its
ride back went around the fight: the round-3 rule). Guard "Earth: ... still guards Skull Woods' third section": pass.
placeWithinReach for a key, Big Key, map, compass, Big Chest (and gold): beside its cell (a nook walked into with
nothing in hand, or an added room), else the nearest cell walked to from it with nothing in hand and no seal, or beside
one of those, else beside it in a line grown before the first, then the old nearest free cell. Water: the entrance's
small-key chest is 1F (0,7), beside (0,8), before the locked flight (guard "Water: ... never behind it": pass); the
Water pin now reads solvable: true, reasons: ["R4: the master key at B1 (5,2) loot can be reached without passing the mini-boss"]. The guard comment no longer calls Water's R2 a property of the data. Nooks (isNookOf) must open on
their room through a side walked with nothing in hand and be reached by no link (Earth's Big Key used to take the Lone
Pot behind the Big Key room's cracked wall).
-
placeShopreaches free cells over doors no key or Bomb opens and no seal (hopsFromwith a passable test); with none,openInFront(entrance). Earth's shop is no longer behind the entrance's cracked wall; the CRACK fixtures' shops moved off the cellar (behind a crack) and the anteroom (behind a small lock).placeExtrasre-reads the board after the shop (a grown line moves positions). -
demoteShortcutWarpsremoves a dropped pair's own moves (the warp's move out of its cell and its landing circle): Storm'smovesno longer list "landing circle 1F(0,0)->1F(2,0)" or "teleport 3F(0,0)->3F(3,0)"; 21 moves (was 23). - dressBoard.ts's header says what is now true.
44 rooms. 2F: the Beetles' flight from the lobby is 2F (1,2), opening on the fight alone (was (2,1)); the two star-tile
pits sit under their fights at (2,0), (2,1). 3F (3 rows, was 4): the Lightning Rod opens beside the stairs down at
(0,2) (the Big Chest screen keeps its stairs), the compass takes the room's empty screen (1,1), the boss warp's circle
is (0,3), the dropped warp's room (1,2). Everything else as round 3. The skipped e2e walk's 2F landing is updated to
(1,2) (not run). ClassicTemples' entrance check reads nowAt (a grown line moves the entrance); its relic and gold
counts include drops.
RED (new expectations against round 3's tool: b48bcaf1's dress*.ts checked out, then restored):
chemx test tests/unit/ClassicDress.spec.ts 5 failed out of 38 (TOWER Boss Key chest, both CRACK shops, DROP landing circle, DROP strict flight)
chemx test tests/unit/ClassicDungeonGuards.spec.ts 18 failed out of 73 (written first: seals lost on Earth and Moon, Moon's flight,
Water's key chest, Earth's landing, the shop, the dropped warp's moves, beyond/reach guards)
GREEN (committed state, one at a time):
chemx test tests/unit/ClassicDress.spec.ts All tests passed (38 passed)
chemx test tests/unit/ClassicTemples.spec.ts All tests passed (28 passed) # 14 in-memory tests moved out, 1 Storm pin added
chemx test tests/unit/ClassicDungeonGuards.spec.ts All tests passed (82 passed)
chemx test tests/unit/ClassicTempleRefresh.spec.ts All tests passed (5 passed)
chemx test tests/unit/ShippedTemplesAudit.spec.ts All tests passed (210 passed)
chemx test tests/unit/TempleSolver.spec.ts All tests passed (53 passed, 1 skipped)
Storm regenerated with the esbuild CLI ("storm-temple: 6 floors, 44 rooms, 2 must-clear, 21 moved, 3 dropped, 0 Bomb
chests"). Audit (npx --yes [email protected] audit --no-index --unroll > /tmp/audit-t7f4.txt, twice;
git checkout -- chemx-ratchet.json after): none of my files under LINE_BUDGET_FILE, CONTROL_FLOW_INLINE_BOOLEAN,
TYPE_COLOCATION or HOOK_RETURN_OVERLOAD (two inline ifs of mine in dressRooms were named after the first run);
counts as the ratchet (INLINE_BOOLEAN 5/4, LINE_BUDGET 36/4, DISPATCH_SWITCH 36, CASCADE_GUARDS 14,
HOOK_RETURN_OVERLOAD 19); only the CLI console.log lines of dress.ts remain (UNGUARDED_LOGGING, as before).
- Moon B1 Bob's Torch (JSON (2,2)) is boxed in on every side; its flight's twin is GT's lobby, so the flight stands in front of the fight (on its south, Big Chest side), not beside it: a hero coming down from the lobby reaches the fight's entry side without fighting it (nothing beyond it opens; the guards check). LTTP landed the hero inside the fight. A flight beside it would need a column inserted inside the grid (corridor rooms across it), not built.
- A boxed-in sealed fight hands out its cell's chests and keys as drops (Ice B2 Ice Right H, Moon Bob's Torch): the hero takes them from the fight's victory rather than from a chest room. My call; the ruling did not foresee it.
- Growth before the first row or column gives
shiftednegative values (Moon B1, Fire 1F, Shadow B1/1F). The specs'nowAthandles them; any other reader ofshiftedmust not assume it is never negative. - Gold ("other") chests follow the chest rule but keep the old nearest-free-cell fallback (not in the ruling's list): Moon's Hope Room gold chest is not reached from its cell on foot with nothing in hand.
- A landing circle for a landing that is no seal keeps
openNear's "nearest added room" as its very last resort; no dungeon reaches it, and the landing guard covers sealed landings only. - The e2e walk stays skipped (round 1's STATUS); its 2F step is updated, not run.
Status: DONE_WITH_CONCERNS (every ruling done; 0 extra cells in all nine; the concerns are below). Commit on
feat/classic-temples-2 (only my paths), tree clean:
3f3ac3d8 fix(temples): in front of a seal means in front of every seal, and the dress step opens no way past its seals
-
dressPlace.frontCells(board, farEnd): the converted cells the dungeon reaches from the entrance with every must-clear fight and the boss shut (dressReach.convertedWalk, the converted walk generalized: a start, a set of barred cells). When the link's far end lies past a seal, the cells reached from that end without crossing one and not from the entrance (so the ride back opens nothing the entrance does not). -
besideInFront(board, from, farEnd)for a sealedfromenters only those cells: first those walked to from the fight (that walk reads locks and cracked walls open, as the dungeon does:walkFrom(..., crossesLocks)), else the front cells of its floor nearest it. Used byopenInFrontfor a flight that faces its fight (far end: the twin,linkEnd(item)) and for a landing circle on a sealed fight (far end: the warp's own cell,circle.item.origin, fromdressLinks.placeLandingCircles). A landing that is no seal keeps the round-4 walk (applying it there grew a row on Storm's 1F for a warp that is dropped anyway). - Moon: Bob's Torch's flight is back at the base spot, B1 (2,7) of the shifted grid = JSON (2,6), beside Speed Torch Upper behind the Hope Room's small lock; Moon stays solvable (R4 only, as pinned). DROP: the fairies ride in from a cell past the climb's seal, so their circle opens on the climb alone, in a row grown above 2F (the DROP expectations moved down a row; the flight still takes the nook, now 2F (1,3)).
ClassicDungeonGuards.spec "opens no way past its seals": with every sealed fight and the boss blocked, the converted
cells the dressed temple reaches (each room mapped back to its JSON cell through shifted/compacted; rooms the
dressing added are walked through, not counted) must be a subset of what the converted JSON reaches with every
must-clear fight and the boss blocked (holes and warps one way, locks ignored). Result: 0 extra cells for all nine
(Moon had 20 lines of diff, the review's 18 cells, before the fix). The in-front guard (standsInFront) now reads the
JSON (frontOf), not the dressed temple that already held the new flight: every converted cell the room reaches on
foot past no seal lies in front of every seal as read from the entrance or from its link's far end.
-
dressDungeondeals the chores last: Bomb chests and extras read the plain layout (layoutNow), thenplanChoresruns on the final board, so a line grown before a floor's first cannot shift the roles. Storm and the other eight are unchanged by it. -
addBombChestNeartakes the near end's slot first and writes the movefrom: nearSlot.at(it follows a grown line). - The guard's
fightFromcounts a fight as kept only while it still seals (lockOnEnter). - dressBoard.ts's header says where a flight that faces its fight goes (beside it, or in front of every seal).
RED (the round-5 guard spec against round 4's tool, adee573d's dress*.ts checked out, then restored):
chemx test tests/unit/ClassicDungeonGuards.spec.ts 2 failed out of 91 (Moon: "opens no way past its seals"; Moon: the in-front check)
GREEN (one at a time, with the committed tool):
chemx test tests/unit/ClassicDress.spec.ts All tests passed (38 passed)
chemx test tests/unit/ClassicTemples.spec.ts All tests passed (28 passed)
chemx test tests/unit/ClassicDungeonGuards.spec.ts All tests passed (91 passed)
chemx test tests/unit/ClassicTempleRefresh.spec.ts All tests passed (5 passed)
chemx test tests/unit/ShippedTemplesAudit.spec.ts All tests passed (210 passed)
chemx test tests/unit/TempleSolver.spec.ts All tests passed (53 passed, 1 skipped)
Storm: storm-temple.ts unchanged (the bundle's CLI rewrote it identically each run; git status clean, and
ClassicTemples' "is exactly what dress.ts writes" passes). Audit (npx --yes [email protected] audit --no-index --unroll > /tmp/audit-t7f5.txt, git checkout -- chemx-ratchet.json after): none of my files under LINE_BUDGET_FILE,
CONTROL_FLOW_INLINE_BOOLEAN, TYPE_COLOCATION or HOOK_RETURN_OVERLOAD; counts as the ratchet (INLINE_BOOLEAN 5/4,
LINE_BUDGET 36/4, DISPATCH_SWITCH 36, CASCADE_GUARDS 14, HOOK_RETURN_OVERLOAD 19); only dress.ts's CLI console.log
lines (UNGUARDED_LOGGING, as before). Files: dressPlace.ts 385 lines, dressReach.ts 117, dressBoard.ts 353,
ClassicDungeonGuards.spec.ts 437.
- Moon's Bob's Torch flight stands behind the Hope Room's small lock and Speed Torch Upper's (the ruled base spot): a hero comes down from the lobby there; the solver clears the temple (R4 only).
- Shadow B1's first row holds one room, an empty dead end: a row was grown before the first for a landing circle whose warp was then dropped (its ride back went around a seal), and the room stays. Out of scope, as ruled.
- Non-boss seals bypassable one at a time, and gold chests, are out of scope (ruled); the round-4 concerns stand.