Skip to content

[feat] 29-F: the waves template, and a knock fix it found - #234

Merged
AlexZ005 merged 2 commits into
release/nextfrom
feat/29f-waves-template
Sep 20, 2026
Merged

AlexZ005 merged 2 commits into
release/nextfrom
feat/29f-waves-template

Conversation

@AlexZ005

Copy link
Copy Markdown
Collaborator

Roadmap 29 follow-up, lane 29f-waves-template: the one roadmap-29 deliverable that shipped without a way to play it. Base release/next (1.15.1).

What

  • [feat] the waves templatewaves joins author-templates MODULE_DEFS (the def is the module's modules/waves/waves.def.json), and game-waves (90 checks, two peers + a late joiner) proves the card is picked in the REAL Games tab, the world arrives whole, Start begins a round, the enemies walk, kills are knocks, wave 2 heals the survivors, a late joiner reads the wave from the triggers handshake, the last wave falls, the shell goes over (won), the run is logged on every peer, and Again restarts. The scene is staged for the scenes repo (cloud-lane-29-staging/games/waves/, README with the release order — read core Scenes feed: jsDelivr treats scenes@v2 as a semver VERSION and never re-resolves a retag (Games tab stale) #230 before touching the ref).
  • [fix] knock: a body under an external physics hold is hit, not carried — found by the template. bodyVelocityOf reported held: !!entry.hold, folding the EXTERNAL hold (the engine yielding to another writer: the waves module walking an enemy every frame, a peer's move stream) into the same flag as a user grab, so on the one peer stepping the world a walking enemy could never be hit (solo probe: eight sweeps, 0 hits, hold:'external' every time) while every other peer hit it fine. Now held means a user hold only; a DRIVEN body refuses the impulse (the next write would erase it) but the hit is logged and sent — the rule the receive side already keeps for a held crate.

Counterfactuals (in the commit bodies)

  • knock fix reverted → game-waves 58/25, red from 4.1/4.2 through the whole round; restored, physics.js sha identical.
  • the def's dusk preset (not a core preset, modules PR Feature/save-load #8) → 1.6 red (studio); fixed to sunset in the paired modules PR (def-only, zip unchanged).
  • waves out of MODULE_DEFS → the build refuses the slug and the suite SKIPs.

Gates (this worktree)

npm run check 336/47 with the error/warning LISTS identical to base · vitest 178/178 · build green (server down) · held: game-dungeon-realms 64/0 · game-untangle 46/0 · game-football 102/0 · game-stars-room 36/0 · knock-physics 77/0 (1.15 "a carried body is never knocked" green) · knock-node 50/0 · modules flights health 99/0 · waves 59/0.

Pairs with

modules PR feat/29f-waves-template (the def preset). Release order: modules devmain (zips on the CDN), scenes row on main/the new ref, then "template": "games/waves" on the modules waves row — with this core fix released before or with the row.

🤖 Generated with Claude Code

AlexZ005 and others added 2 commits September 20, 2026 12:18
- src/lib/physics.js: `bodyVelocityOf` reports `held` for a `user` hold only (the grab it was
  documented for) and adds the raw `hold` kind. `held: !!entry.hold` folded the EXTERNAL hold —
  the engine yielding to another writer (a module walking a body every frame, a peer's move
  stream) — into "somebody is carrying it".
- src/lib/knock.js: `evaluateProbe` still skips a carried body; on the initiator `fireKnock`
  treats a body that refused the impulse because it is DRIVEN (`hold === 'external'`) as a real
  hit — logged and sent like every other, the impulse alone refused (the next write would erase
  it) — which is the rule the receive side already keeps for a held crate (noteRemoteHit logs,
  applyHit refuses, independently). A body nobody drives that still refuses (gone, not dynamic)
  sends and spends nothing, as before.
- Found by the waves template (29-F): its enemies are dynamic bodies the waves module walks each
  frame and its damage source is `hit`. On the one peer stepping the world every sweep read 0 hits
  with the body at `hold: 'external'` (a solo probe, eight sweeps), while a non-initiator (no body,
  `held: false`) hit them fine — the host could not damage a walking enemy.

Counterfactual (game-waves against the staged scene): `held: !!entry.hold` restored -> 58/25, red
from 4.1/4.2 (the initiator's slow knock reads 0 hits) and 4.3/4.4 (nothing for B to log) through the
whole round (6.1-6.12); fix restored, physics.js identical. knock-physics 1.15 (a CARRIED body is never
knocked) held in the same battery.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… suite

- scripts/author-templates.cjs: `waves` joins MODULE_DEFS (modules/waves/waves.def.json, emitted by
  `npm run build:waves`; both modules in installModules, so the file's derived requirement list
  names health + waves). Built against the lane at 5215; byte-stable across two builds
  (compare-authored SAME). Staged for the scenes repo in cloud-lane-29-staging/games/waves/
  (scene 11701 B + thumb 1690 B + index-row + README with the release order and the #230 ref note).
- tests/e2e/game-waves.test.cjs (90 checks; two peers + a late joiner; skip-never-fail): the card is
  picked in the REAL Games tab (the feed's index.json + scene served through a route, since the row
  is not released) and loadRemoteScene replaces a non-empty world; the file's 10 objects, both
  modules, the sunset env, the play block (grab/grounded/simOnPlay) and the knock block; the
  modules derive 4 enemies on a 3-wave curve, a goal, three spawn pads, five health rows; B over the
  handshake; Start -> playing on both -> the HUD screen; the run is ON, the first enemy WALKS (+z)
  and B places it where A does; HUD Text reads the Waves Value nodes and the bar the player's
  health; kills are KNOCKS through core's feedProbe (a slow sweep = one pulse, a hard one = three),
  the hit in B's hit log and B's ledger agreeing, B's knock (a non-initiator) completing wave 1, the
  kills rows per peer, wave 2 healing the survivors one death's worth; the late joiner reads wave 2
  and the same ledger from the triggers handshake; waves 2 and 3 fall one enemy at a time -> DONE on
  all three -> over (won) -> the over screen -> ONE run logged on every peer; Again -> a new round
  with every enemy back at full health.
- .claude/skills/e2e-verify/SKILL.md: the suite in the GAMES-TAB line. The suite reads core's own
  SCENES_BASE fallback out of sceneTemplates.js, so the #230 ref move follows by construction.

Counterfactuals: the def's env preset `dusk` (not a core preset; PR #8's def) -> 1.6 red (studio),
fixed to `sunset` on modules feat/29f-waves-template (def-only, module.js and the zip unchanged);
`waves` out of MODULE_DEFS -> the build refuses the slug and the suite SKIPs (no scene to test);
the knock fix reverted -> the initiator's knocks 4.1/4.2/4.5/4.6 red (its own commit).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@AlexZ005
AlexZ005 merged commit 2515c3b into release/next Sep 20, 2026
4 checks passed
@AlexZ005
AlexZ005 deleted the feat/29f-waves-template branch September 20, 2026 10:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant