CB-WP-0006 T06: K10 replay bundles, --replay, and AM-7 re-earned
INTENT design decision 8 of 10, unimplemented for six passes. cb-sim had no flag parsing at all, so --replay had nowhere to go. The bundle is manifest + commands.log + initial.snapshot + expected.yaml, dev-only behind the scenarios feature and charged to AM-4b. The command stream goes through the K11 framing built in T05, so a truncated bundle is detected rather than replayed short — the two tasks compose rather than duplicating. The reviewer's D2 correction was real: this was not "a directory of four files". Pass carried only the end state, RunOutcome::Failed was a formatted String, and scenario.rs created an EventLog, appended to it and never read it. All three had to change. The first round trip failed to reproduce, and the cause is worth keeping: state_hash_hex over a serde_json::Value is a different canonical form than over the typed aggregate — Value's map is key-sorted, a struct serializes in declaration order. The bundle was written with one basis and verified with the other. A round trip written to recompute its own comparison value would have PASSED this bug; it failed because the recorded hash came from the producing process, which is control 2's entire purpose. make replay-test implements ADR-0005 §6's four controls, 14/14: a committed deliberately-failing fixture outside the corpus with covers: [] so it neither fails `make sim` nor inflates AM-1; a tampered recorded hash must fail; a log short by one byte and a corrupted length prefix must be rejected; and a mutated manifest seed must fail — which bites only because replay re-derives the initial state from seed+setup and checks it against the recorded snapshot, since restoring from the snapshot alone would leave the seed inert. Plus a control on the controls: the bundle must still replay after every mutation is reverted. AM-7's hash-identical clause is re-earned. The probe records a hash per per-game segment and replays each from its own genesis; folding from the wrong seed now fails. That is the clause ADR-0005 §4 withdrew as mutation-proven inert. The scaling >= 0.9x clause is still unenforced, so AM-7 stays PARTIAL — reported, not rounded up. Kernel coverage 15/18 -> 16/18. facts-check immediately caught the spec's copy of that number going stale, on a number that moved the same hour. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
6037467478
commit
1edadac9a2
17 changed files with 721 additions and 35 deletions
|
|
@ -268,3 +268,69 @@ never demonstrate.
|
|||
with AM-2, AM-5 and AM-9 added, AM-6 moved to enforced, and the headline
|
||||
total corrected from 4 to 8 — it had gone stale within the same workplan
|
||||
that produced it.
|
||||
|
||||
## CB-WP-0006-T06
|
||||
|
||||
**Delivered: K10 replay bundles, `cb-sim --replay`, and AM-7's withdrawn
|
||||
hash clause re-earned.**
|
||||
|
||||
INTENT design decision 8 of 10, unimplemented for six passes. `cb-sim` had
|
||||
no flag parsing at all, so `--replay` had nowhere to go.
|
||||
|
||||
**The bundle** (`crates/cb-game-runtime/src/replay.rs`, dev-only behind
|
||||
`scenarios`, charged to AM-4b): manifest, `commands.log`,
|
||||
`initial.snapshot`, `expected.yaml`. The command stream goes through the
|
||||
**K11 framing built in T05**, so a truncated bundle is detected rather
|
||||
than replayed short — the two tasks compose rather than duplicating.
|
||||
|
||||
**The D2 correction the reviewer forced was real.** This was not "a
|
||||
directory of four files": `Pass` carried only the *end* state, `RunOutcome::Failed`
|
||||
was a formatted `String`, and `scenario.rs` created an `EventLog`,
|
||||
appended to it and never read it. All three had to change.
|
||||
|
||||
### The bug that proves the round trip is load-bearing
|
||||
|
||||
The first round trip **failed to reproduce**. Cause: `state_hash_hex` over
|
||||
a `serde_json::Value` is a **different canonical form** than over the
|
||||
typed aggregate — `Value`'s map is key-sorted, a struct serializes in
|
||||
declaration order. The bundle was written with one basis and verified with
|
||||
the other.
|
||||
|
||||
Worth stating plainly: a round trip that had been written to recompute its
|
||||
own comparison value would have **passed** this bug. It failed precisely
|
||||
because the recorded hash came from the producing process — control 2,
|
||||
which exists for exactly this.
|
||||
|
||||
### The four controls, all executable
|
||||
|
||||
`make replay-test`, **14/14**:
|
||||
|
||||
| control | how it is proven |
|
||||
|---|---|
|
||||
| something actually fails | a committed fixture in `scenarios/fixtures/` (outside the corpus, `covers: []`, so it neither fails `make sim` nor inflates AM-1); exactly one bundle produced; all four files present **and non-empty** |
|
||||
| hash read from the bundle | tamper only the recorded hash → replay fails. A recomputed comparison would still pass |
|
||||
| truncation detected | log short by one byte → rejected; length prefix corrupted → rejected |
|
||||
| replay can fail | mutate the manifest seed → rejected. This bites only because replay re-derives the initial state from seed+setup and checks it against the recorded snapshot; restoring from the snapshot alone would leave the seed inert |
|
||||
|
||||
Plus a control on the controls: the bundle must still replay after every
|
||||
mutation is reverted, so the suite cannot leave the tree broken.
|
||||
|
||||
### AM-7 re-earned
|
||||
|
||||
The probe now records a hash per **per-game segment** and replays each
|
||||
from its own genesis. Folding a segment from the wrong seed fails:
|
||||
|
||||
```text
|
||||
AM-7 hash-identical UNMET: replaying segment seeded 42 (0..64) did not
|
||||
reproduce its recorded state hash
|
||||
```
|
||||
|
||||
That is the clause ADR-0005 §4 withdrew as mutation-proven inert. The
|
||||
`scaling >= 0.9x` clause is still unenforced, so AM-7 stays **PARTIAL** —
|
||||
reported, not rounded up.
|
||||
|
||||
**Kernel coverage 15/18 → 16/18**; K10 is no longer unlinked. `facts-check`
|
||||
immediately caught the spec's copy of that number going stale — the DFD
|
||||
gate earning its place on a number that moved the same hour.
|
||||
|
||||
**M-D1-MUT: 8 of 14** (unchanged; AM-7 remains partial).
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue