diff --git a/findings/control-flow/hive-creation-rng.md b/findings/control-flow/hive-creation-rng.md index 40b8625..d578c32 100644 --- a/findings/control-flow/hive-creation-rng.md +++ b/findings/control-flow/hive-creation-rng.md @@ -279,37 +279,78 @@ buried, because it is the kind of thing that looks like instrument perturbation `NumOwn` and every other field checked. The two `TechTree/St` bytes that also move are that choice's consequence, and `Summary/Checksum` follows. -The `hooks=off` control was then run from the same input, and it is the reason this section is worth -reading. **It produced a third answer.** +The `hooks=off` control was then run from the same input, and it produced a **third** answer. -| run | instrument | `(Autosave).sav` | size | player 3's `ResTNm` | -|---|---|---|---|---| -| the original 2026-09-07 session (live game, never loaded) | phase-2 shim, `hooks=trace` | `ab4ac2d7e2977260` | 66,739 | `BIO_GnMod` | -| this lane | full L1 hook set | `62061918176e3441` | 66,739 | `XNC_TrnsLir2` | -| this lane, control | **`hooks=off` — nothing installed at all** | `e43ec1d2b443c101` | **66,740** | `XNC_TrnsMorr2` | +**Lane L5 found the same thing independently on VM146 the same day**, from the other direction — as a +by-product of its own rule-19 control — and owns the write-up: +`findings/subsystems/turn1-to-turn2-nondeterminism.md`. This lane's two runs are corroboration and +they widen its spread, so the union is recorded here and the analysis is not repeated. -Players 0, 1 and 2 pick identically in all three (`""`, `IND_Waldo`, `DRV_PlsFiss`). Only player 3 -moves, and it moves **with the instrument removed as well**. +| run | instrument | `(Autosave).sav` | that player's `ResTNm` | +|---|---|---|---| +| the original 2026-09-07 session (live game, never loaded) | phase-2 shim, `hooks=trace` | `ab4ac2d7e2977260` | `BIO_GnMod` | +| lane L5 run B | `ComputeBudget=compare` | `ab4ac2d7e2977260` | `BIO_GnMod` | +| lane L5 run A | same hooks, different constant in `ours` only | `7fc9e6ab46b47794` | `XNC_TrnsHvr2` | +| lane L5 control | `hooks=off` | `62061918176e3441` | `XNC_TrnsLir2` | +| **L1** | full L1 hook set | `62061918176e3441` | `XNC_TrnsLir2` | +| **L1 control** | **`hooks=off`** | **`e43ec1d2b443c101`** | **`XNC_TrnsMorr2`** | -**So the turn-1 → turn-2 transition of this game is not deterministic across processes, and no hook -is responsible.** The three picks are three different tech ids, two of them species-tagged variants -of the same node (`XNC_TrnsLir2` / `XNC_TrnsMorr2`), which is the signature of a selection over a -container whose order is not fixed — a pointer-keyed map or an unstable tie-break — rather than of a -generator draw. The strategic generator's trajectory was **identical to the historical game's** in -the instrumented run, so whatever chooses here does not draw from it. +**The two rows in bold are what this lane adds, and the second one sharpens lane L5's conclusion.** +L5 argued from "the `hooks=off` control is a *third* value, not one of the other two". This lane ran +`hooks=off` again and got a **fourth** value — so **`hooks=off` is not self-consistent with itself +across processes**, which is a stronger statement than "no hook is responsible" and rules out the +whole class of explanations in which some particular instrument configuration selects the pick. +Four distinct outcomes over six runs, and this lane's instrumented run happens to coincide with +L5's uninstrumented one, which is the clearest possible demonstration that the hooks are not the +variable. -Two consequences, both of which matter more than this lane: +Players 0, 1 and 2 pick identically in every run (`""`, `IND_Waldo`, `DRV_PlsFiss`). Only the +shadow-empire player moves. In this lane's instrumented run the strategic generator's trajectory was +**identical to the historical game's** — same word positions, and the hive draws produced the +historical `NextQ` values — so whatever chooses here does not draw from it. -* **`turn1-state.sav` must not be used as a determinism-oracle input.** `determinism-oracle.md` - establishes byte-identity for `ref-turn2 → turn 3` and was never run on turn 1; that claim is - intact and this is a different pair. -* **The standalone milestone has a target that the original itself does not always hit.** A - reimplementation cannot be held to a byte match on a turn where the original disagrees with itself. - Which turns those are is now an open question with one known member. +### 6.2 It is bounded, and the strategic generator is not what varies -None of this touches §0–§5: the RNG numbers were taken on a run whose generator trajectory matches -the historical game word for word, and the same hook set reproduces the oracle exactly on the -adjacent turn. +**No claim in §0–§5 rests on an autosave diff.** The hive result is a *generator word position* +measured by two instruments that share no code path — a region ledger reading `left` around a phase +boundary, and a set of detours keyed on return address — plus the entry-side prediction those +numbers were checked against. Diffing `turn1-state → turn2` bytes is not part of it, and would not +have been able to answer the question either way. + +The variation is small and exactly located. Every pairwise leaf comparison over the three post-turn +saves this lane holds gives **4 differing leaves out of 35,032**, with the leaf count and the whole +tree structure identical: + +``` +/Summary/Checksum (derived) +/Sim/Player/TechTree/St 2 <-> 3 (the node it stopped researching) +/Sim/Player/TechTree/St 3 <-> 2 (the node it started researching) +/Sim/Player/ResTNm BIO_GnMod | XNC_TrnsLir2 | XNC_TrnsMorr2 | XNC_TrnsHvr2 +``` + +so the reference pair remains usable for everything except one shadow empire's research selection. +This matches lane L5's characterisation exactly, on a fourth sample. + +**And it is not the strategic generator.** This is the part this lane can add that a save diff +cannot: in the instrumented run the strategic generator's trajectory was **identical to the +historical game's** — the two hive draws produced the historical `NextQ` 31 / 29, the next turn's +slip produced 32 / 30, and the absolute word positions 192 and 211 are the ones +`tail-rng-ledger.md` §2.1 records for the same game. A pick drawn from `S+0x16c` would have moved +that trajectory. It did not. + +There is an obvious next place to look, and this lane's own draw-site table points at it: **8 words +per turn are drawn from a *different* `Mars::RNG` in the same process** — the `StrategyClient`'s at +`client+0x134`, from `0x00578cf0`, `0x005798e0` and `0x0069dbb0` (`tail-rng-ledger.md` §11.2 first +identified these and correctly excluded them). That object is **not serialised**, so if the AI's +pick draws from it, its seed is not in the save and a per-process variation is exactly what one +would expect — which is lane AI1's "seeded from an unseeded global" reading, arriving from a +different direction. Two rows of that table appear on every turn of both saves measured here: +`draw_site_words_other_rng = 8`, `draw_site_calls_other_rng = 8`. + +**The experiment that would settle it** is a boundary hook on the AI research-selection site with a +region over `client+0x134` rather than `S+0x16c`, on two fresh processes: if the two runs enter it +with different generator state, the cause is found. That is one hook and one afternoon, and it is +the difference between "the reference pair has four unstable leaves" and "we know why". ## 7. What this does NOT settle (rule 15) diff --git a/findings/subsystems/determinism-oracle.md b/findings/subsystems/determinism-oracle.md index d8749f2..19d7c13 100644 --- a/findings/subsystems/determinism-oracle.md +++ b/findings/subsystems/determinism-oracle.md @@ -5,21 +5,20 @@ Question: "load the same save, press End Turn, and the resulting autosave is byt game processes, with and without an intervening manual save, and also identical to the autosave the *original* (non-loaded, freshly created) game wrote in the earlier session. -> **SCOPED BY LANE L1, 2026-09-08 — the oracle is a property of THIS PAIR, not of End Turns.** -> (`findings/control-flow/hive-creation-rng.md` §6.1.) Every run below starts from the **turn-2** -> state. Lane L1 ran the same experiment one turn earlier — load `turn1-state.sav` -> (`a3f9dc4b…`, which is this game's turn-1 pre-turn autosave), one End Turn — three times, and got -> **three different post-turn autosaves**: `ab4ac2d7…` (the original live session), `62061918…` (full -> hook set) and `e43ec1d2…` (**`hooks=off`, nothing installed at all**). The whole difference is one -> field: player 3's research target `ResTNm`, which reads `BIO_GnMod` / `XNC_TrnsLir2` / -> `XNC_TrnsMorr2` across the three. Players 0–2 pick identically every time, and in the instrumented -> run the strategic generator's trajectory matched the historical game word for word. +> **SCOPED, 2026-09-08 — the oracle is a property of THIS PAIR, not of End Turns.** Every run below +> starts from the **turn-2** state. Lanes L5 and L1 independently ran the same experiment one turn +> earlier — load `turn1-state.sav` (`a3f9dc4b…`, this game's turn-1 pre-turn autosave), one End Turn +> — and across six runs got **four different post-turn autosaves**, including **two different results +> from `hooks=off` with nothing installed at all**. The whole difference is one shadow-empire +> player's research target `ResTNm` plus its two tech-status words and the derived `Checksum`; +> players 0–2 pick identically every time and the strategic generator's trajectory is unchanged. > -> So: **the turn-1 → turn-2 transition of this game is not deterministic across processes, and no -> hook is responsible.** Nothing below is wrong — but "load the same save, press End Turn, and the -> autosave is byte-identical" is verified for `ref-turn2 → turn 3` and **falsified for -> `turn1-state → turn 2`**. Anyone building a byte oracle must pick the pair deliberately, and the -> pairs in this document plus `verify/results/shim/tailrng/` are the ones that hold. +> Nothing below is wrong. But "load the same save, press End Turn, and the autosave is +> byte-identical" is verified for `ref-turn2 → turn 3` and **falsified for `turn1-state → turn 2`**. +> Pick the pair deliberately: this document's pair and the two in +> `verify/results/shim/tailrng/` are the ones that hold. Full account: +> `findings/subsystems/turn1-to-turn2-nondeterminism.md` (lane L5, owner) and +> `findings/control-flow/hive-creation-rng.md` §6.1 (lane L1, the two extra runs). ## Verdict