From ce8b3e66b4acf4556fe27340ef27ac72aba90893 Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 8 Sep 2026 19:07:13 -0400 Subject: [PATCH] RB: lane CB's real capture replays to the same result, and brings the seeds and the heap payloads CB's VM146 capture goes through the JSON->tcb adapter and the replayer unchanged and reproduces this lane's canonical result from a separate run on a different guest: 108 -> 62, closed 46, regressed 0, ModCount 24. It carries the first AI seeds any capture has held (32/496/512), and its deep dump closes two gap rows: list 8's route is [272] and list 10's vector is [1728], a ship the input save already contains. --- findings/subsystems/turn-command-replay.md | 35 ++++++++++++++++--- verify/results/turncommands/cb-turn2to3.tcb | 38 +++++++++++++++++++++ 2 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 verify/results/turncommands/cb-turn2to3.tcb diff --git a/findings/subsystems/turn-command-replay.md b/findings/subsystems/turn-command-replay.md index 0381865..b8984de 100644 --- a/findings/subsystems/turn-command-replay.md +++ b/findings/subsystems/turn-command-replay.md @@ -125,9 +125,34 @@ overrides it to `?` and says why in its own docstring; **CB should drop the list `RECORDS` rather than rely on the adapter to mask it**, because the JSON is the capture of record and a wrong typing in it will outlive this note. CB's `raw_words` are unaffected and remain right. -Two things CB's dump has that L4's does not, and that the `.tcb` format already has fields for: -`aiseed` (the per-client construction seeds) and `aivec` (the heap vectors — which turn list 8's -route from `v1` into `v1:` and remove one whole row from the gap list in §4). +### 1.2 CB's real capture, run + +CB's own VM146 capture landed while this lane was closing and it goes straight through the adapter +and the replayer unchanged: `verify/results/turncommands/cb-turn2to3.tcb`. It reproduces this +lane's canonical result exactly — **108 → 62, closed 46, regressed 0**, `ModCount` 24 — from a +completely separate run of the game on a different guest. It also brings two things L4's dump +could not: + +* **The AI seeds, observed live:** netId **32 → `0x9dfad635`**, **496 → `0xb482b2d8`**, + **512 → `0xfb81e993`**, all `pinned=false` (observed, not forced). These are the first seeds any + capture has carried, and they are what makes this a turn record a future `game/ai` can be + *re-derived* against rather than replayed from. +* **The heap payloads**, which close two rows of the gap list below outright: + * **list 8's route is `[272]`** — one hop to system 272. Lane L4 §5.3 recorded this as + "`turn3-state.sav`'s waypoint says 272 but the capture does not prove it". It is proved now. + * **list 10's counted vector is `[1728]`** — a **ship** id, and one that exists in the input + save. `{systemId 288, fleetId 34, ships [1728]}` is now a typed reading with values, and + "assign these ships to this fleet at this system" fits all three. Still not a proof of the + command's *name* — the effect has never been observed — but the payload's type no longer + leaves it open. + + Those two elements move from `incomplete` to `declined` in the replay report: the capture is now + complete and the *subsystems* are what is missing. + +CB's capture also does the one thing neither of my files did and every future capture must: +it records the input save's hash **bound to the output autosaves' hashes**, both of which match +the published determinism oracle, with a `hooks=off` control run named. That binding is what makes +a capture usable as a byte-match oracle at all. **The converter.** `tools/aiorders_to_tcb.py` turns lane L4's shim dump into a `.tcb` mechanically: it applies the per-list field mapping, undoes the one list whose writer runs backwards, reinterprets @@ -238,9 +263,9 @@ but not applied. |---|---|---|---| | 1 | **list 3 build, list 1 design** | **ship construction.** No phase in this engine builds a ship. The command carries a queue ordinal, a design id and a system; the effect is `srb`/`sri`, `Maint`, the savings debit, a hull id and `ShipIDs`. Nine leaves on the canonical pair. | engine work; lane B6/E2 have the map | | 2 | **list 1, list 3, list 8, list 10, list 14** | **the client's id allocator.** The build order names design **18** and the fleet order names fleet **34** — objects that do not exist in the input save, allocated *client-side before submission*, while the server's own master counter (`NMnx`) issued 1712 and 1776 the same turn. **Two id spaces**, and the small one is part of the wire protocol. A reimplementation that allocates on apply produces a structurally correct save with every AI-created id wrong. | **a watchpoint**, not a week of reading: break on the write that produces 18 and 34 | -| 3 | **list 8 fleet move** | **the route's hops.** The capture records the route's length and not its contents, because the dump does not follow the vector. One more indirection in the dumper. Also needs (2): the route belongs to a fleet the save does not contain. | one dumper change | +| 3 | ~~**list 8 fleet move** — the route's hops~~ | **CLOSED by lane CB's deep capture (§1.2): the route is `[272]`, one hop.** What remains is row 2 — the route belongs to a fleet the input save does not contain. | done | | 4 | **list 5 system rates** | **the memory field order of the rates frame** (§3). One correspondence pinned, six unread. | one UI run, or one save-sourced capture | -| 5 | **list 10** | **a name and a meaning.** `{systemId, fleetId, counted vector}`; "assign these ships to this fleet at this system" fits and has never been tested. The vector's contents are unread. | a hook on `0x0088bed0` | +| 5 | **list 10** | **a name and a meaning.** The payload is fully read now (§1.2): `{systemId 288, fleetId 34, ships [1728]}`, and 1728 is a ship the *input* save already contains. "Assign these ships to this fleet at this system" fits every word. The **effect** has still never been observed, so it is still not named. | a hook on `0x0088bed0` | | 6 | **list 14 fleet task** | **what the two modes do.** Two elements per AI fleet order, modes 0 then 1; the interface deposits one, mode 0 only. The *cost* is settled; the *effect* is not read at all. | a hook on the inlined applier | | 7 | **list 23 population** | **the `Population` body**, 24 bytes behind a vftable that the capture window does not follow. Free in `ModCount`, so it has never been forced. | one dumper change | | 8 | **the research-target gate** | **the techId → tech-name map.** The wire carries an integer (144, 90, 288); the save carries a name. The client resolves it *off the command* and passes a `char*`. The ids are not `index * 16` and are not indices into anything we hold. Today the capture can carry the observed name and the replay TRANSCRIBES it — reported in its own column, because that is not a reimplementation. **Three data points now exist**: 144 → `IND_Waldo`, 90 → `DRV_PlsFiss`, 288 → `XNC_TrnsMorr2`. | a watchpoint at the gate payload, or a read of `0x006c8580` | diff --git a/verify/results/turncommands/cb-turn2to3.tcb b/verify/results/turncommands/cb-turn2to3.tcb new file mode 100644 index 0000000..56855c5 --- /dev/null +++ b/verify/results/turncommands/cb-turn2to3.tcb @@ -0,0 +1,38 @@ +tcb 1 +meta source cb-c1-turn2to3.txt +meta input turn2-state.sav +meta input_sha256 ab4ac2d7e2977260a4de916f65c7ecc6dd5b0094dac4bb51241317232ea17ab4 +meta output (Autosave EndTurn).sav 66732 bb4fd9ac89f41e3bc0db2af08b18ce83417521ac4bcee695fc9fa6ce16e30948 oracle=True +meta output (Autosave).sav 67219 978041acd168b56ed8eb3f5e42e78d5e70eae6e6517d75e659a5eb7ca3d60921 oracle=True +meta control c0-hooksoff-turn2 (hooks=off, same guest, same click path; byte-identical to this run) +meta lane CB capture_version 1 build cb2-20260908T2251Z guest VM146 +meta extension vN:a,b -- a vector whose contents ARE known; bare vN still means unknown and must still be refused +meta batch seq=2 n=8 +seed 32 0x9dfad635 +seed 496 0xb482b2d8 +seed 512 0xfb81e993 +block 0 16 +gate 0 rate 0.25 +block 1 32 +gate 1 rate 0.8 +list 1 3 1 +elem 1 3 0 i2 i18 i288 i0 +list 1 5 1 +elem 1 5 0 i288 f0.0 f1.0 f0.0 f0.0 f0.0 f0.0 i0 +list 1 8 1 +elem 1 8 0 i34 v1:272 +list 1 10 1 +elem 1 10 0 i288 i34 v1:1728 +list 1 14 2 +elem 1 14 0 i34 i0 b1 +elem 1 14 1 i34 i1 b1 +list 1 23 1 +elem 1 23 0 i288 ? v6:12422480,1,2,862581960,1000000000,0 +block 2 496 +gate 2 rate 0.8 +block 3 512 +gate 3 rate 0.8 +block 4 0 +block 5 0 +block 6 0 +block 7 0