Handover: FABLE-SOLO-12 — three lifecycle fixes and a soak against the roster wave

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
type-two 2026-07-22 02:28:48 +10:00
parent 164b4480c5
commit 6d2fc56bfb

View File

@ -1655,3 +1655,63 @@ collected $19, baggie pocketed with incident ✓ · walk-out at the entry anchor
### Note
`entry` anchor is (72,360) — tile (4,22)-ish, NOT the exit tiles at x=1; the
sweep walk-out and the night-mode exit both key off `VENUE.anchors.entry[0]`.
---
## SESSION — FABLE-SOLO-12 · 2026-07-22
**Branch:** main (solo, Fable) · **Gate:** lint ✓ build ✓ test ✓ (735 tests, 49 files)
**Deployed:** https://monsterrobot.games/not-tonight/ (curl 200)
This session ran ALONGSIDE the parallel session that landed the roster wave
(41e93d0..d4f8024). No feature work from me — I soak-tested, found three real
defects, fixed them, and re-verified the merged tree.
### Fixed 1 — the dev route killed the door (main.ts, NightScene)
`showScene()` stopped `'Door'` (it was in the stop list) and then declined to
restart the already-active `'Night'`. Pressing **N** mid-night therefore left a
live Night driving a SHUTDOWN Door: an unplayable black screen with no way back.
`'Floor'` was not in the list at all, so it survived — the asymmetry is what made
it look like a launch race. Now only ROOT scenes route (`Roster/Night/Parade/
FloorDemo/JuiceDemo`), and re-pressing a route key restarts the target, so N
means "fresh night". `NightScene.teardown()` now stops Door and Floor, making
real the ownership main.ts always claimed in a comment.
### Fixed 2 — every floor-start shift booted INERT (NightScene)
`applyLocation()` moves flags but emits nothing; the initial call is
`applyLocation(role.startLoc)`. FloorDemoScene latches `present` when it binds
the night context — and now that the night preloads all 28 prop textures, the
floor's own loader finds nothing missing and binds SYNCHRONOUSLY, i.e. BEFORE
that delayedCall(0) runs. So `present` latched `false` for bartender, glassie
and DJ: floor visible, camera live, and every interaction dead. The audio filter
also stayed in door mode while you stood on the dancefloor. The night now emits
`night:phaseChange` + `audio:location` for the starting post. Verified all four
roles: bartender→taps, glassie→floor, dj→decks, door→door.
### Fixed 3 — the floor carried last night into this one (FloorDemoScene)
Phaser reuses scene INSTANCES across restarts, so class-field initialisers run
once per GAME. A DJ shift left `djMode` set and the next night booted with
movement locked and the keyboard eaten; last night's `puddles` kept slipping
people through sprites Phaser had destroyed; `spotted`/`cutOffDealt`/`jointDealt`
marked fresh arrivals as already handled (patron ids restart with the run).
`resetNightState()` in `create()` now wipes all of it. NOTE: the roster wave's
own bar state (tabs/tips/orders/staffReadyAt) was already reset correctly in
bindNight — only the older floor state leaked.
### Soak (frame-stepped, ~1.5h game time, zero errors)
Door object count flat (~70), floor objects track crowd, vibe oscillates 50→67→54
(live pressure, not pinned). Night ended legitimately on AGGRO 97.8 after I
abandoned the rope all night and Kayden waved through 13 people including a
17-year-old — the fail narration is correct.
### Verified of the roster wave
Roster board renders and routes; BARTENDER shift starts on the floor at the taps;
order → SERVE → pour meter → vibe +4.2 → `barServe` incident. Old saves still
load (GameState shape unchanged, `loadGame` validates `v===1` and falls back).
### Harness note for future sessions
`window.game.loop.step()` does NOT advance real asset loading. A night that
preloads 28 textures needs real wall-clock time before Door/Floor launch — step,
then `await sleep(~900ms)`, then step again. Two "critical bugs" this session
were my own harness outrunning the loader; check `scene._queue` and
`load.totalToLoad` before believing a scene is stuck.