One mode owns the court: the duel can no longer start inside a horde, and the game has tests

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Fable 5 committed 2026-08-11 12:55:37 +02:00
1 parent 4569981365
commit 05930f0877
4 files changed
+210 -5

No files matched your search

+25 -1
View File
@@ -5,7 +5,7 @@ everything they specified is shipped, and what still matters from them is record
long history, `~/.claude/projects/.../memory/splatter-tennis-history.md` is auto-loaded; for the
detail of any individual change, read the git log.
Last updated 2026-08-08 (testgroup round: popup policy, ghost hand, barrel economy). **Start with "How to work on this", "OPEN — leftovers" and "LATER —
Last updated 2026-08-11 (the third freeze: court-ownership guards + `node test.js`). **Start with "How to work on this", "OPEN — leftovers" and "LATER —
shipping it"** (all three just above the CLOSED sections) — the first tells you how Oliver's feedback
should be handled, the second is everything known to be outstanding in the game, the third is the
demo/store/campaign plan, which is decided but entirely unbuilt. All four playtest rounds are closed
@@ -376,6 +376,30 @@ zombie (now an occasional opponent, `TUNE.racketEvery`, not the every-game fixtu
`RETURNED`, `DOUBLE KILL`) is a footnote to something you already watched happen. Sharing the loud
FACE with the milestone cards is right; sharing their SIZE made every footnote read as a milestone.
## Session log: the third freeze — court ownership enforced, and the first tests (2026-08-11)
Oliver hit the horde freeze a THIRD time, earlier in a run: **a sudden-death duel started inside a
live horde.** Welded on the right side, no drag (duel's `pretoss` kills steering), no serve
(`G.horde` blocks taps), spawns kept coming. The full chain: kills still score during the SET card
beat (spawn director keeps running there), a game won mid-card re-armed `G.clearing`/`G.afterClear`
while `pendingHorde` was already latched → horde started with a clear parked → mid-horde the gun
mowed the court to an empty frame between spawns → `G.clearing && !blockers` advanced the beat
**mid-horde** → `duelDue` fired `startDuel()`. The watchdog was blind to it by design: its signature
includes `horde.t`, which ticks every frame, so the state always looked alive.
Fixed at the chokepoints, not the call sites:
- `update()`'s hand-clear advance now requires `!G.horde` — a latched clear waits for `endHorde`.
- `startDuel()` and `startHorde()` hard-refuse while any other mode owns the court
(interlude/horde/bossFight). All present and future callers inherit this.
- `splatPoint()` is a no-op during the duel — `resolveInterlude` is the duel's only exit. (A machine
or leftover killed mid-duel used to bank score and could re-enter `proceedAfterClear` mid-duel.)
- **Invariant net** in `watchdog()`: if horde+interlude ever coexist anyway, or the phase leaves
`rally` during a horde, it repairs on the spot and logs `INVARIANT` into `G.missLog`.
**The game now has tests: `node test.js`** — headless Node, real game modules, stubbed platform
(DOM/WebAudio/storage). Seven cases pin the ownership contract, including a scripted repro of the
field freeze and the injected-corruption repair. Run them before touching `gameplay.js` beats.
## Session log: the testgroup round — popups, ghost hand, barrel economy (2026-08-08)
First round of feedback from the small test group (via Oliver), seven items, all landed.