The replica knows each strike's window, and its blast ends by the same tick #140

Owner

Tracker: #3774

Step 2 of plan #3560 (a launched nuke reveals where it lands to every player). The replica now knows each strike's reveal window on its local clock, and the blast's drawn effect ends on the tick that window does. Nothing new draws yet: step 3 feeds the replica's sight sources to the fog. The step changes no server code.

What it delivers

  • Landed strikes. Replica keeps the landed strikes that each Nukes carries. Each one's due tick is on the local clock: the frame's tick less its ticksSince.
  • Sight sources. Replica.reveals() gives the shared rule's sight sources (addReveals, src/shared/nuke.ts) at localTick, from the strikes in flight and the landed ones. A strike's disc holds from the frame that lists it through local tick due + BLAST_TICKS − 1, across the frame that moves it from flight to the landed list, and none at due + BLAST_TICKS.
  • One detonation. The replica's record of the strikes it has detonated still guards the frame that moves a strike from flight to the landed list, so the strike detonates once. The record is renamed from landed to detonated, since landed now holds the wire's landed strikes.
  • Detonation dates (D5). A detonation learned from a frame, such as a Snapshot that unlists a strike after its due tick, is dated at the strike's due tick, not at the frame's tick. The blast's effect then ends on the tick the reveal does, and a blast learned of more than BLAST_SECONDS late draws only its crater.
  • Late joiners. A landed strike the replica never saw in flight records no detonation, as before.

Tests

  • src/client/replica.test.ts
    • A strike the replica steps through: its sight sources hold the disc from the frame that lists it (tick 10) through due + BLAST_TICKS − 1 (489), across the frame at 40 that lands it, and none after. It detonates once.
    • A later join's Snapshot at 52 carrying a strike landed at 40: the disc from 52 through 489, none after, and no detonation.
    • The Snapshot at 52 that lands a strike due at 40 now dates its detonation at 40, and the test's name says so.
  • src/client/render/nuke.test.ts: a NukeLayer synced from a replica's strikes and detonations at each local tick plus a draw phase of 0 and of 0.99. Its drawn parts (nukes.root.children) hold the strike's effect alone at every tick from its listing through due + BLAST_TICKS − 1, and nothing from due + BLAST_TICKS on. Two cases: a detonation the replica steps through, and a strike it saw in flight whose landing it learns from a Snapshot 12 ticks after the due tick.

Failing before: on the step's base (425535f), the late-Snapshot nuke case fails with 24 wrong samples: the effect is still drawn at ticks 760–771 at both phases, 12 ticks (the Snapshot's lateness) past the reveal's end. The dating test fails on its tick (52 against 40), and the two reveal tests fail since the base replica has no reveals(). The step-through nuke case passes on the base, as expected.

Mutation check (whole-tree copies of the head, one edit each, running replica.test.ts and nuke.test.ts):

mutant result
control 50/50 pass
reveals() reads only the strikes in flight fails both reveal tests
reveals() reads only the landed strikes fails the step-through reveal test
landed due as tick + ticksSince fails the later-join reveal test
the detonation record's check dropped from the landing frame fails the step-through reveal test and the held-ahead/rewind test
a frame's detonation dated at the frame's tick fails the dating test and the late-Snapshot nuke case

Checks

  • Map Yard: src/mock/map-yard.ts imports only replica.ts's types (Fall, Strike), and render/nuke.ts imports only sameStrike from it. The yard's dist (mock/map.html, vite build from git archive trees) is byte-identical between base 425535f and head 92f7e19: 61 files, the same digest. So the yard draws as before, and the Map Yard bench was not run.
  • Nuke yard: its dist differs, since it bundles the replica. It steps its replica through the landing, so its detonation is dated on the due tick as before. nuke.phone.ts runs in full.
  • Play stays as step 1 left it:
    • src/ai/player.ts reads from its replica only world, playerId, units, credits, training, cities, layouts, siloClocks(), flights() and localTick (besides feeding it with apply and advance). It reads no detonation, no landed strike and no sight source. The host's shadow of each remote session reads only units.
    • npm run bench (src/bench/net.ts bundled per arm with esbuild, wan, seed 11), every scenario (idle, battle, assault, economy, cities, churn, siege) at 128 and 256: all 14 cases are identical to the base in hash, gameHash, commandHash, the command list and every client's row, raw and deflated bytes included. So the 14 AI matches were not rerun.
  • Gates (on m5, head 92f7e19):
    • fast, this run's gate #1 (tracker gate run 280): passed, npm test 979/979.
    • full, this run's gate #2 (tracker gate run 281): passed, npm test 979/979 in 27.4 s and test:phone 180/180, nuke.phone.ts included.
Tracker: [#3774](https://sak.swipelab.com/tasks/3774) Step 2 of plan #3560 (a launched nuke reveals where it lands to every player). The replica now knows each strike's reveal window on its local clock, and the blast's drawn effect ends on the tick that window does. Nothing new draws yet: step 3 feeds the replica's sight sources to the fog. The step changes no server code. ## What it delivers - **Landed strikes.** `Replica` keeps the landed strikes that each Nukes carries. Each one's due tick is on the local clock: the frame's tick less its `ticksSince`. - **Sight sources.** `Replica.reveals()` gives the shared rule's sight sources (`addReveals`, src/shared/nuke.ts) at `localTick`, from the strikes in flight and the landed ones. A strike's disc holds from the frame that lists it through local tick `due + BLAST_TICKS − 1`, across the frame that moves it from flight to the landed list, and none at `due + BLAST_TICKS`. - **One detonation.** The replica's record of the strikes it has detonated still guards the frame that moves a strike from flight to the landed list, so the strike detonates once. The record is renamed from `landed` to `detonated`, since `landed` now holds the wire's landed strikes. - **Detonation dates (D5).** A detonation learned from a frame, such as a Snapshot that unlists a strike after its due tick, is dated at the strike's due tick, not at the frame's tick. The blast's effect then ends on the tick the reveal does, and a blast learned of more than BLAST_SECONDS late draws only its crater. - **Late joiners.** A landed strike the replica never saw in flight records no detonation, as before. ## Tests - **src/client/replica.test.ts** - A strike the replica steps through: its sight sources hold the disc from the frame that lists it (tick 10) through `due + BLAST_TICKS − 1` (489), across the frame at 40 that lands it, and none after. It detonates once. - A later join's Snapshot at 52 carrying a strike landed at 40: the disc from 52 through 489, none after, and no detonation. - The Snapshot at 52 that lands a strike due at 40 now dates its detonation at 40, and the test's name says so. - **src/client/render/nuke.test.ts**: a NukeLayer synced from a replica's strikes and detonations at each local tick plus a draw phase of 0 and of 0.99. Its drawn parts (`nukes.root.children`) hold the strike's effect alone at every tick from its listing through `due + BLAST_TICKS − 1`, and nothing from `due + BLAST_TICKS` on. Two cases: a detonation the replica steps through, and a strike it saw in flight whose landing it learns from a Snapshot 12 ticks after the due tick. **Failing before:** on the step's base (425535f), the late-Snapshot nuke case fails with 24 wrong samples: the effect is still drawn at ticks 760–771 at both phases, 12 ticks (the Snapshot's lateness) past the reveal's end. The dating test fails on its tick (52 against 40), and the two reveal tests fail since the base replica has no `reveals()`. The step-through nuke case passes on the base, as expected. **Mutation check** (whole-tree copies of the head, one edit each, running replica.test.ts and nuke.test.ts): | mutant | result | |---|---| | control | 50/50 pass | | `reveals()` reads only the strikes in flight | fails both reveal tests | | `reveals()` reads only the landed strikes | fails the step-through reveal test | | landed due as `tick + ticksSince` | fails the later-join reveal test | | the detonation record's check dropped from the landing frame | fails the step-through reveal test and the held-ahead/rewind test | | a frame's detonation dated at the frame's tick | fails the dating test and the late-Snapshot nuke case | ## Checks - **Map Yard:** src/mock/map-yard.ts imports only replica.ts's types (`Fall`, `Strike`), and render/nuke.ts imports only `sameStrike` from it. The yard's dist (mock/map.html, vite build from `git archive` trees) is byte-identical between base 425535f and head 92f7e19: 61 files, the same digest. So the yard draws as before, and the Map Yard bench was not run. - **Nuke yard:** its dist differs, since it bundles the replica. It steps its replica through the landing, so its detonation is dated on the due tick as before. nuke.phone.ts runs in `full`. - **Play stays as step 1 left it:** - src/ai/player.ts reads from its replica only `world`, `playerId`, `units`, `credits`, `training`, `cities`, `layouts`, `siloClocks()`, `flights()` and `localTick` (besides feeding it with `apply` and `advance`). It reads no detonation, no landed strike and no sight source. The host's shadow of each remote session reads only `units`. - `npm run bench` (src/bench/net.ts bundled per arm with esbuild, wan, seed 11), every scenario (idle, battle, assault, economy, cities, churn, siege) at 128 and 256: all 14 cases are identical to the base in hash, gameHash, commandHash, the command list and every client's row, raw and deflated bytes included. So the 14 AI matches were not rerun. - **Gates** (on m5, head 92f7e19): - `fast`, this run's gate #1 (tracker gate run 280): passed, `npm test` 979/979. - `full`, this run's gate #2 (tracker gate run 281): passed, `npm test` 979/979 in 27.4 s and `test:phone` 180/180, nuke.phone.ts included.
agra merged commit 6b8535d2b6 into task/3560-a-launched-nuke-reveals-where-it-lands-t 2026-10-24 09:09:25 +03:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
agra/mini-alert!140
No description provided.