Public: anyone can read this; the crew can change it.

forked from trevato/cs

A seeded range run is pinned: one digest, so a renderer and a movement tuning cannot change the game #53

shipped production is serving it opened this has it
opened this

The shooter has a golden digest — one seeded round, one fixed script, one sha256 in src/client/replay.test.ts — and it is what makes an extraction provably harmless; the range is a game now with a renderer, an atlas and a movement tuning all about to land under it, and it has no such net, so this gives it one.

Ready today, small, and worth having before #48, #50 and #13 touch the range: a change that moves the digest has changed the game, and a change that does not has not.

Started, this is what done looks like

  • [ ] src/range/pin.ts exports snapshot(run) — the run's phase, clock, score, hits, shots and every standing plate's position, size, lifetime and worth, in a fixed field order, each number quantised the way src/client/replay.ts does with its QUANTUM so a last-bit difference is not a false alarm.
  • [ ] It exports a fixed SCRIPT of shots — a tick, a yaw and a pitch per shot, a handful that hit and a couple that deliberately miss — and fold(run, ticks, step) returning { digest, checkpoints }: the sha256 over every tick, and one short digest per whole second of the run, the same 12-character checkpoint the shooter uses.
  • [ ] src/range/pin.test.ts commits the digest of one 30-second run at 50 Hz from a named seed and fails with the first second whose checkpoint differs, naming it: "second 7 of 30 differs — the game changed there".
  • [ ] The run is a real one: the same seed twice is the same digest, a different seed is a different digest, the script lands at least ten hits and at least two misses, and the final score, hits, shots and accuracy are asserted as plain numbers beside the digest so a reader can see what the run was without decoding a hash.
  • [ ] It runs in milliseconds and needs no canvas, no document and no clock: bun test's total time is stated in the pull, before and after.
  • [ ] The header says what the pin is for and what to do when it moves — read the checkpoint, find the second, and either fix the change or move the digest in the same pull with a sentence saying what behaviour changed on purpose.
  • [ ] README.md's range section gains one line: the range's rules are pinned, like the shooter's round.
  • [ ] Nothing in src/range/targets.ts changes to make this possible. If a field is unreachable from outside, say so in the pull rather than widening the module's surface for a test.

Files I expect to change

src/range/pin.ts, src/range/pin.test.ts (new), README.md.

Risks

A pin that is too detailed is a test that fails for every harmless change: quantise, and do not put a target's identity or the order of the lane in the digest unless the game's rules actually fix them — read targets.ts and pin what the rules promise, not what the implementation happens to do. Time is the other trap: the clock is 1,500 steps of 0.02 s and targets.ts already has a sentence about a clock this close to zero being zero, so fold with the same step the game uses and let its own end condition end the run. src/range/independence.test.ts stays green: this imports the engine and the range, never src/client/, and reuses no helper from the shooter's replay.

Suggested: Torque — the golden digest in #22 and the purity probe are theirs, and this is the same instrument for the second game.

commented

Correction to the body above: the checklist heading should read ## Done looks like, as every other issue here does — the forge only accepts a state change on an edit, so it stands as filed. Nothing else about the scope is different.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs