# Resolution — the AI client seed is fresh per process; the tie hypothesis is dead, the byte-match is not - **Type:** resolution (course-setting; no measurement taken here) - **Trigger:** lane L1's P7 falsified — `findings/subsystems/ai-client-seed-is-per-process.md` - **Date / author:** 2026-09-08 · re-resolver - **Touches:** `backlog.md` §2 (Rung C and the mechanism paragraph), board rows 240 / 255 / 331 / 333 / 335, `determinism-oracle.md` (closing paragraph), `ai-turn-logic.md` §5.1 + P1, `ai-order-capture.md` §3.1–§3.2, `lane-ai1.json::g_GlobalRNG`, lane L4 and CB briefs, `method-rules.md` (new rule 25) --- ## 0. Decision 1. **The variation on `turn1-state → turn2` is a seed effect.** Each AI `StrategyClient`'s generator is seeded at construction with a 32-bit word that differs in every process. The coordinator's tiebreak-by-ASLR inference, and lane AI1's all-zero-seed derivation, are both overturned. The instrument is exonerated (§2). 2. **The byte-match ambition survives, and in a stronger form than the tie-set claim.** The original's decision layer is MT19937 from that one word — a generator we already own bit for bit — so the AI is a deterministic function of **(save, per-client seed)**. A deterministic `game/ai` that *takes the seed as an input* can byte-match **every** run whose seeds were captured, not only the runs where a tiebreak happens to agree. That answers the user's standing question — *make it deterministic and the old approach still pays* — with a yes, on the condition that the seed is treated as part of the input. Rung C is restated accordingly (§5). 3. **The tie-set claim is rescued as a statement and open as a result — and not on "equal cost".** Where seeds were never captured (the historical `turn2-state.sav`) no one can reproduce the run — the original included. There the claim is membership in the **outcome set** of a random pick, S(D), with a four-part verification statement (§3.1). Lane L4 has one arm (k = 6, XNC) and `BIO_GnMod` proves a second arm exists whose producer is unidentified, so "we can name all k" is **to prove**, not proved. That is the fallback, "C-set". 4. **One probe, before anything else is redirected: pin the three client seeds and run the creation turn twice — through L4's resolver instrument, then sweep seeds.** Prediction: byte-identical autosaves, same pick under the same seed, a measured word cost inside `TryResearchCandidate`. If it holds, the seed is the only per-process input on that turn, `turn1-state → turn2` returns to the oracle set (with seeds), `game/ai` has a well-posed exact target, and the sweep names the `BIO_GnMod` arm. The seed's *source* is not the probe. §3.1, §4. 5. **Rule 19 gets a companion, rule 25:** a control must agree with itself across two fresh processes before it can exonerate or indict anything, and "one of N moves" says nothing about mechanism. Draft in §7. --- ## 1. The surprise, stated precisely Loading `turn1-state.sav` in two freshly launched processes, with `Mars::RNG::Seed` and `StrategyApp::RunAI` detoured, produced the same eight records in the same order with the same net ids — and **three different seeds for the three AI clients in each process, none shared between processes** (`0x75F692C0 / 0xF2EDAC21 / 0x165A2ADB` vs `0x414F415E / 0x10B94E78 / 0xC218DBF8`). The prediction committed before the build was "identical, and zero". It was wrong on its first falsifier row. The evidence is as strong as it looks. The `Seed` hook records the post-state of the object it seeded; the one call that takes `seed = 0` gives `mt0..mt2 = 2443250962 / 1093594115 / 1878467924` in both processes, so the hook reproduces a known input to a known state and did not randomise anything. The build was fresh (`l1seed-20260908T2206Z`, lane L1's own dist). The workload is load-only, so no End Turn logic is involved — this is the construction path and nothing else. Two further things the raw trace says that the report does not spell out: - **The three seeds within one process are unrelated words** (high bits `0x75`, `0xF2`, `0x16`), not three reads of a clock microseconds apart. They are successive *outputs of a generator*. That is exactly what AI1 read at `OnMessage+0x955` — `mov ecx,0xaf6e58 ; call NextUInt` — so the call site reading stands and the "never seeded" reading falls: **`g_GlobalRNG` is live and per-process.** Something initialises it that a scan of the six direct `RNG_Seed` sites cannot see — rule 16's shape (an inlined MT init, or a state copy), or the object at 0xaf6e58 is not the one being drawn. Inference; §4.2 names the cheap check. - **A fourth per-process seed exists before any AI client** — record #2, `seed = 0xf22aac3a` / `0x16612cc3`, on a heap object nobody has identified. It is either the global's source, a sibling consumer of it, or an unrelated per-process generator. On `ref-turn2` it changes nothing save-visible (seven fresh processes agree there); on other workloads it is unbounded. ## 2. The instrument — exonerated, and the reason is worth keeping Three lanes' instruments cannot be the cause and the seed probe shows why: - L5's pair A/B carried **identical hooks** and disagreed; L1's instrumented run **coincided** with L5's un-instrumented one; L4's runs differed with and without hooks. No hook configuration selects the pick. - `ref-turn2 → turn3` reproduces byte-for-byte under every hook set tried (H, L1, L4, F, V) and under none. The instruments are behaviour-neutral on a workload where the game is self-consistent. - The seed probe's built-in control (`seed = 0` → identical state) shows the `Seed` detour itself does not perturb the object it observes. **But no `hooks=off` run on `turn1-state` was a control of anything** — L5's, L1's and L4's `hooks=off` runs gave three *different* files (`62061918…`, `e43ec1d2…`, `d59bb9f2…`). Each lane cited its single `hooks=off` run as "the un-instrumented value"; together they show the un-instrumented game has no single value there. The exoneration above rests on the identical-hooks pair and on `ref-turn2`, not on those runs. That is the gap in rule 19 — §7. ## 3. Standing claims, one by one | claim | where | verdict | scope / correction | |---|---|---|---| | Per-client `Mars::RNG` at `StrategyClient+0x134`; all six AI-band `NextInt` sites plus `cl_Chance`/`cl_RandRange` reach it; **zero AI draws on the strategic generator** | AI1 §5, board 240 (first half) | **survives** | L1's hive run has the strategic trajectory identical to the historical game while the pick varies — the strongest confirmation available | | "`g_GlobalRNG` is never seeded; every draw returns 0; every AI client is seeded with 0" | AI1 §5.1, board 240 (second half), `lane-ai1.json::g_GlobalRNG` | **overturned** by measurement | The author flagged it as arithmetic and wrote the falsifier that fired ("run-to-run different values mean it is time- or address-seeded"). Rule 2 working as designed. Lane H's counter-indication (rejection loop ran on that generator, impossible for an all-zero state) is now confirmed and should be credited | | AI1's five consumers of `g_GlobalRNG`: `SNMRunAI`, `RunCombatRound+0x60f`, `0x007c2fa0+0xc84`, `0x0079ea90+0x73` (`Chance`), `0x005b9f00+0xc0` | `lane-ai1.json` | **survives as a list; its meaning flips** | Each is now a **per-process input** to whatever it feeds. `ref-turn2` bounds them to "no save-visible effect on that turn" (seven processes). The combat consumer has never been cross-process tested on a battle turn — §6 | | "P2 HELD: the AI is fully reproducible from a save alone" | AI1 §8.1, board 255 | **qualified with scope** | True of `ref-turn2 → turn3`, where every AI already holds a target and no decision depended on a draw. False as a general statement, as L5/L1/L4 showed. Already superseded by row 331; the row should say so | | `turn1-to-turn2-nondeterminism.md` — three runs, four leaves, instrument exonerated | L5 | **survives**; cause now known | Its "what was not established: the cause" is answered: the per-client seed. Its `hooks=off` row is a sample, not a control (§2) | | Determinism oracle on `ref-turn2 → turn3` | `determinism-oracle.md`, board 50/253 | **survives unchanged** | The closing "Mechanism (inference…)" paragraph must be replaced with the seed finding | | Coordinator's mechanism: "only one of three varies ⇒ pointer-ordered tie under ASLR, not a time seed which would move all three" | backlog §2 last para, board 331 (5), `determinism-oracle.md` last bullet | **overturned** | All three streams move. A seed is visible only where a decision depends on a draw; 32 and 496 never reach the candidate walk (L4 §3.2), so their picks are stream-insensitive by *code path*, not by luck | | Rung C = "deterministic `game/ai` whose choice is provably inside the original's **tie set**; k enumerable" | backlog §2, board 333 | **restated** (§5) | The *conclusion* that the outcome space of the one varying decision is small and nameable survives; the *mechanism* is a draw, so it is the support of a random pick, not a tie. And the exact form — byte-match given the seed — is now available and is stronger | | L4 §3.2: three producers; only 512 reaches `SelectResearchTarget`; candidate vector length 1 = a category `{2,12}`; fallback not taken; k = 6 for the XNC family from data; 4 of 6 observed inside | L4 | **survives** (measured parts) | Its interpretation — "taking whichever member it reaches first … the per-process quantity is order" — is **overturned**: the per-process quantity is the client stream inside `TryResearchCandidate 0x006c8580`. Inference until the draw is seen; the L4 correction in §8 says how | | L4's engine recommendation (canonical by tech id; claim membership in a nameable set) | L4 §3.2 | **survives as C-set** | Needs the `BIO_GnMod` arm accounted for (2 of 6 observed picks are outside the XNC set), i.e. the category itself is probably drawn | | Lane Z: "residual outside the two drivers is exactly zero" | `tail-rng-ledger.md` §0/§2 | **qualified with scope** (L1 did it in place) | True of every turn with hives already present; on the creation turn `BeginProcessTurn` draws one `NextInt` per new hive, with the rejection loop live. The standalone's replay interval starts at `BeginProcessTurn` (§6) | | Rule 19's `hooks=off` control | `method-rules.md` | **qualified** | Valid only on a workload where the un-instrumented game agrees with itself across two fresh processes. Rule 25 (§7) | | "The decision layer is not deterministic, and does not need to be" | backlog §2 | **qualified** | It *is* deterministic given the seed. "Does not need to be" holds for lockstep (decisions travel as commands); for us the seed is an input, not noise | | Lockstep MP is consistent with a per-machine AI seed | board 331 (2) | **survives** | Only the machine hosting an AI client draws its seed; peers see commands. Prediction for L2 when convenient: the combat seed (the `RunCombatRound` consumer) must be host-distributed in the SNM stream, or MP battles would desync | ## 3.1 The coordinator's follow-up, ruled on **Is the tie-set claim rescued?** *In form, yes; in content, not yet — and not on the grounds proposed.* Three rulings: 1. **Do not re-ground it on "an identical-cost family".** The six *tier-1* XNC techs cost 2000 RP each, but the observed picks are their *tier-2* successors at 13,000–30,000 RP — L4's own load-bearing detail is that the costs differ and the resolver still varies. Equal cost is not what makes the outcome set a set. What makes it a set is that the resolver's output is a function of the client stream over a finite candidate collection: **S(D) = the support of a random pick**, and k is the size of that support. Ground the claim on the draw and its bound, which the probe reads; never on cost. 2. **"We can name all k" is not claimable today, and `BIO_GnMod` is why.** Two of six observed picks (L5 run B, and the original session that wrote `turn2-state.sav`) are outside the XNC six. L4 captured the candidate stream once, in a run that went to producer C. The honest reading of the six observations is: **S(D) ⊇ XNC-six ∪ {`BIO_GnMod`}**, with the producer of `BIO_GnMod` unidentified. The likeliest shape, stated as inference: in the `BIO_GnMod` runs producer A or B returned non-null for player 512 — gated by a draw on the same client stream — and the walk was never entered; then S(D) = A's outputs ∪ B's outputs ∪ C's arm, and naming k means reading three producers' gates, not one resolver. Finite, cheap, and *not yet done*. Carry k = 6 as L4 says: **to prove**. 3. **The verification statement, exactly.** For a turn T from save X, let D be a decision whose output depends on the client stream (on `turn1-state`, exactly one: player 512's research target). Then: > **C-set.** (i) *Derivation:* S(D) is listed **before any sweep**, from the code of every > producer that can set D and from shipped data plus the save (the available-tech set is a > function of X, so S is per-save, not a constant). (ii) *Canonical pick:* `game/ai` emits a > fixed member of S(D) — lowest tech id, the quantity the command carries. (iii) *Containment:* > every observed original run's D is in S(D). (iv) *Falsifiable content:* a sweep of **pinned > seeds** — the seed is now a knob — produces no D outside S(D), and reaches every member of > S(D) whose derived probability is not negligible. (iii) alone is a tautology if S is just the observed set; (iv) is what makes it a claim. Today (i) is done for one arm, (iii) holds 6/6 only by admitting `BIO_GnMod` on observation, and (iv) has not been run. C-set is therefore *rescued as a statement and open as a result*. C-exact (§5) does not depend on any of this and is the primary form. **On "a clean control" (R2 = `hooks=off` bytes).** Not a control — rule 25. Two runs landing on the same one-of-k pick is a ~1/k event per pair, and with pairs compared across L5, L1 and L4 one coincidence is expected (L1's instrumented run also coincided with L5's `hooks=off`). It is *consistent* with neutrality; the exoneration rests on L5's identical-hooks pair and on `ref-turn2` reproducing under every hook set, as §2 says. **Is the next probe inside the resolver rather than at the seed source?** *Yes on the source — it is not the probe — but the resolver probe is only an experiment if the seed is pinned.* Without the pin, two runs of L4's instrument with two unknown seeds cannot separate "draws from the stream" from "reads something else per-process". With it, the same run answers both "what is per-process about it" (same seed ⇒ same pick settles that it is the stream) and "what does it iterate" (the `left` delta and the draw's bound name the arm's k). So the one probe is the pin *through* the resolver, one run, both instruments — §4. ## 4. The one probe — pinned seeds through the resolver **Pin the three AI client seeds to constants; run L4's research instrument with a `left` region over `client+0x134` at `TryResearchCandidate 0x006c8580`; load `turn1-state.sav` in two fresh processes; End Turn; compare autosaves and the `aicand`/pick/word-cost lines.** Then sweep seeds. Why this and not the alternatives the coordinator listed: - *Where the seed comes from* only matters for reproducing files whose seeds were never logged — which is impossible whatever the source turns out to be. For every future capture the `RunAI` hook already logs the seed. - *Whether the outcome space is enumerable* is answered "yes, per decision, from the producers' gates and the draw's bound" the moment the mechanism is a draw — and it becomes irrelevant to exactness once the seed is an input. It stays relevant only for C-set, which is the fallback, and there it needs (i)–(iv) of §3.1, which the sweep supplies. - *Whether the varying empire's candidate set is tied* is already answered by L4: the vector has one element. There is nothing to tie. The pin probe separates the two hypotheses that are actually live: - **H1:** the per-client seed is the *only* per-process input to this turn. Pinned seeds ⇒ byte-identical `(Autosave).sav` across processes, `(Autosave EndTurn).sav` still `a3f9dc4b…`, strategic word positions still 192 (hive draws unaffected). - **H2:** something else per-process feeds the pick or the turn — the fourth seeded object (record #2), a clock read inside the AI, an address-keyed container. Pinned seeds ⇒ the autosaves still differ. *Where* they differ localises it: the same four leaves ⇒ H2 is inside the research pick; anything else ⇒ a per-process input outside the AI, which nobody has predicted. **Implementation, for whoever runs it (minutes, not a lane):** lane L1's `l1seed` shim already detours `RNG_Seed` and sees the seed argument. Add `seed.pin=,,`: when the detour's return address is `0x0078304b` (the instruction after `call RNG_Seed` at `0x00783046` in the `StrategyClient` ctor), replace the seed with the next pinned value, in call order (the order is deterministic — eight records, same order, both runs). Log the replaced and original values. The existing post-state fields verify the pin: the three `after` states must be identical across processes, which is the built-in control. Use process 1's own values (`0x75F692C0`, `0xF2EDAC21`, `0x165A2ADB`) so a match against any file L1 already holds is possible in principle. Then: **(i)** `ref-turn2` once with the pin active — expect `978041acd168b56e…`; that turn's decisions are stream-insensitive and the pin must not change that (rule 19 for the pin itself). **(ii)** `turn1-state` twice, fresh processes. **(iii)** If (ii) differs in the four known leaves only, extend the pin to record #2 (return address of whichever site seeds it — the trace has its `this`) and rerun. That is the whole bisection. **(iv)** The sweep, same build: quit to menu and reload advances the pin table (`RunAI` runs again on every load, so each reload is a fresh sample without a relaunch — ~30 s per sample on L4's path). Ten to twenty pinned seeds, each logging: which of the three producers returned non-null for player 512, the `aicand` line, the word cost on `client+0x134` inside `0x006c8580`, and the pick. That is §3.1's (iv) — the first `BIO_GnMod` sample names its producer, and the word cost and bound name k for the arm that ran. Predictions to commit before the build: H1 holds; same pinned seeds ⇒ same producer, same `aicand`, same word cost, same pick, byte-identical autosave; different seeds ⇒ same `{2,12}`, same cost, different pick; `TryResearchCandidate` costs ≥ 1 word on `client+0x134`; the `BIO_GnMod` samples come from producer A or B, not from the walk; word positions 192 / 211 unchanged throughout. ### 4.1 What the probe buys beyond the answer - If H1 holds, `turn1-state → turn2` **with pinned seeds** is a byte oracle again — and it is the **only corpus pair that exercises `BeginProcessTurn`'s hive draw**. The standalone gets its creation-turn reference back. - The same run, with L4's research instrument and a `left` region over `client+0x134` around `TryResearchCandidate`, turns L4's inference into a measurement in one shot (§8). - CB's C3/C4 runs on `turn1-state` become reproducible captures: seeds + stream + autosave, all from one process, is the record RB needs. ### 4.2 Secondary probes, in order, none of them a week 1. **The seed's source:** one hardware write watchpoint on `0xaf6e58+4` (`mt[0]`) armed at `Application::Initialize` entry, dropped at first `SNMRunAI`. The hit's return address is the seeder. Static cross-check for free: scan the image for the MT init multiplier `0x6C078965` at instruction boundaries — an inlined `init_genrand` that the six-site `RNG_Seed` scan could not see (rule 16, exactly). 2. **The other four consumers of `g_GlobalRNG`:** entry probes (rule 20), cheapest on a battle save — §6. 3. **Record #2's owner:** the `Seed` detour already has its `this`; one `NextInt`/`NextFloat` detour recording `this` (lane H's own suggestion for the client generators) names its consumers. ## 5. Rung C, restated Replace backlog §2's Rung C bullet and the mechanism paragraph with: > - **Rung C — `game/ai` as a deterministic function of (save, per-client seed).** The original's > AI is not non-deterministic; it is MT19937 from one 32-bit word per AI client, drawn once at > construction (on load, or at `CreateGame`) from a per-process global generator, and the > generator is one we already own bit for bit. Two verification strengths: > - **C-exact.** Given the seeds captured from an original run (three words, logged by the > `RunAI`/`Seed` hook; `sots_turn --ai-seed =,…`), our AI's command block equals > that run's block element for element and the autosave byte-matches. This holds on **every** > captured run, because nothing else per-process reaches the turn — that "nothing else" is > what the pin probe establishes, and it is the user's framing made literal: *make the AI > deterministic and the old approach still pays.* Precondition: `game/ai` consumes the client > stream in the original's order and count, including draws whose result never reaches the > save (the surrender `Chance` at 0 %, the one-shot schedule at `agent+0x36c`, the > `NextInt` rejection loops). A per-client draw ledger, lane Z's instrument with `this` > recorded, is the prerequisite; the site table already shows 8 words/turn on these boards. > - **C-set.** Where seeds were never captured — the historical `turn2-state.sav`, which no > process including the original can reproduce — our canonical pick is a member of the > **outcome set** of the one seed-sensitive decision: the image of the client stream under > the resolver, named from the candidate set and the draw's bound. Lane L4 has the XNC arm > (k = 6, four observed, all inside) and one arm unaccounted for (`BIO_GnMod`, 2 of 6 > observations). The claim is "a member of a set we can name", as before; the mechanism is a > draw, so the set is the support of a random pick, not a set of equal-score candidates. > > Mechanism, **measured** (lane L1): the per-client generator at `StrategyClient+0x134` is seeded > from `NextUInt` on the global generator at `0x00af6e58`, which is live and per-process; the > seed is not in any save. Only one of three empires' picks *shows* the effect because only one > reaches the candidate walk (lane L4); the other two are stream-insensitive by code path. The > earlier "pointer-ordered tie under ASLR" inference was wrong and is withdrawn. Two things Rung B keeps regardless: `--turn-commands` replay is still the no-AI path and still the right thing for RB to build; and the canonical pair stays `turn2-state → turn3-state` until the pin probe promotes the creation turn. ## 6. The other two items in the report **`BeginProcessTurn` and the standalone.** Yes, the replay interval starts at `BeginProcessTurn`, not `ProcessTurn`. What else assumed the drivers bound the turn: `sots_turn`'s "walk all three drivers' phase order" (backlog §1 `app` row) has no slot for it — add a fourth interval with `RegisterHives` (the five constants L1 read live, the two predicates, `NextInt(10)` *with its rejection loop*) and the `TickHives` slip. Lane Z's calibration numbers for the standalone generator (16 vs 20 / 18) were taken on turns where the interval costs 0 and are unaffected. The pre-turn autosave precedes `BeginProcessTurn`, so any standalone that starts from a pre-turn save must create the hives itself; only the creation turn shows it, and that turn is the pair the pin probe restores. **`g_GlobalRNG`'s combat consumer.** `RunCombatRound+0x60f` draws on the same per-process generator — most plausibly the seed for `Mars::CombatSim+0x108`. Lane Z's one instrumented battle (turn 55, auto-resolved) cost the strategic generator 0 words, in **one** process. No battle turn has ever been compared across two processes; lane H's `z2-endturn` seven-process agreement was on a turn with no encounter. So **combat turns are not yet known to be cross-process reproducible**, and this is the single most likely place the seed effect reappears. It does not touch Rung A (no battle on the canonical pair). Backlog §5's "a battle with `res->+4` clear" workload should add: run it twice in two processes, and if it differs, pin the global (`RNG_Seed(0xaf6e58, K)` from the shim after `Initialize`) and rerun. **`hooks=off` and rule 19** — §7. ## 7. Draft rule 25 for `method-rules.md` > ## 25. A control that disagrees with itself is not a control > > Lane L5 ran `hooks=off` once on `turn1-state → turn2`, got a third value, and read it as "the > instrument is not the cause". Lane L1 ran `hooks=off` again and got a fourth; lane L4 a fifth. > All three were right about the instrument — by luck. None of those runs was a control, because > the un-instrumented game does not reproduce itself on that workload: the cause was a per-process > seed on the AI clients, present with no hooks and invisible to all of them. > > Two consequences. **(a)** Rule 19 says `hooks=off` in **two** fresh processes. This is why: cite > the agreement, not the run. If the two disagree, report "the workload is non-deterministic > un-instrumented" as its own result, and take the control on a workload that does agree with > itself (`ref-turn2`, `z2-endturn`) or pin the per-process input first. A control workload has to > be *chosen*, and its self-consistency stated next to the number. > > **(b)** "One of N moved" is not evidence about the mechanism. A seed moves every stream; it is > visible only where a decision depends on a draw. The coordinator inferred "tie, not seed" from > two stable empires and one moving one; the two stable empires were on a code path that never > reaches the draw. Count the decisions that depend on draws, not the objects that changed — and > when the inference has been written into the roadmap, write the probe that would falsify it on > the same line. Ranked by damage: the wrong inference reached backlog §2, `determinism-oracle.md`, two board rows and two lane briefs for about a day, and was caught by a written prediction before any engine work followed it. Below rule 24, above nothing yet — append as 25. ## 8. Course — lane by lane **L4 (VM145, live).** Redirect mid-flight. Send: > L1's seed probe came back: every AI client's generator is seeded with a fresh per-process word > (three different seeds per process, none shared across processes), so the varying pick is a > **seed effect**, and the tie/arrival-order framing in your brief and in §3.2's interpretation is > withdrawn — your own P10 falsification already pointed there. Your measured facts stand: three > producers, only 512 reaches the walk, one candidate `{2,12}` that is a category, fallback not > taken, k = 6 for the XNC arm. What changes is what the second capture is for. Do not chase > order. Add a region over the **client generator at `client+0x134`** (`left` / `next_index` — > lane Z's `RngLedger` shape) at entry and exit of `TryResearchCandidate 0x006c8580`, and if the > `aicand` dump can carry it, the bound of any `NextInt` it makes. Then run the creation turn > **twice with the seeds pinned** — L1's `l1seed` Seed detour, return address `0x0078304b`, three > constants — first both processes on the same seeds (prediction: same `aicand`, same word cost, > same pick, byte-identical autosave), then once on different seeds (prediction: same `{2,12}`, > same cost, different pick). Then sweep: quit-to-menu and reload advances the pin table, so ten > to twenty seeds cost ten to twenty loads, no relaunch; log **which producer returned non-null > for 512** on each — the `BIO_GnMod` arm is almost certainly producer A or B gated by a draw, and > its first appearance under a known seed names it. That turns "the resolution varies" into "the > resolution draws n words with bound b, and k = b+1 for this arm; the other arm is producer X > behind gate G". Carry k = 6 as *to prove* until the sweep has produced `BIO_GnMod` under a known > seed. Your C-set recommendation survives as the fallback for references whose seeds were never > logged; the exact form — `game/ai` given the seed — is now the primary Rung C, and the > per-client draw ledger you would be starting here is its prerequisite. **CB (VM146).** Not a redirect; one addition to the capture format and one to the run list. The capture must carry the **three AI seeds** (`RunAI`'s `rng_seed` per net id) next to the block set — they are three words and they are the difference between a log file and a reproducible pair. Add **C5 = C3 with pinned seeds, twice**; if the pin probe holds, C5's block + autosave + seeds is the first fully reproducible creation-turn record, and RB byte-matching it is the real test of "deterministic given the stream". P5 as written (C3/C4 differ in exactly one word) stands and is still worth running unpinned once. **RB (engine).** No redirect. Add a `--ai-seed =,…` input alongside `--turn-commands`, unused until `game/ai` exists, so the capture format and the CLI agree from the start; nothing else changes. **L2 (VM141, multiplayer combat).** Untouched. One prediction to note for later, not now: the combat-sim seed must travel host → peer in the SNM stream, because `RunCombatRound` draws it from a per-machine generator. If L2's capture already has the message, it names the consumer for free. **L3 (VM144, trade/spy tail draws).** Untouched — its subject is the strategic generator, which this finding leaves exactly where lane Z put it. **VM140 is free.** The pin probe goes there, on the `l1seed` build, before L4's second capture depends on it. Whoever runs it owns rule 25's first application: two fresh processes, agreement cited. **Docs to correct in place (rule 11):** `determinism-oracle.md` last bullet; `ai-turn-logic.md` §5.1 (annotate, keep) and P1 (mark falsified, credit the falsifier row); `ai-order-capture.md` §3.1 last two paragraphs and §3.2's "reaches first" interpretation; `lane-ai1.json::g_GlobalRNG` prototype (drop "never seeded / every draw returns 0", keep the consumer list, set status `mapped`); `turn1-to-turn2-nondeterminism.md` "what was not established" (answered). --- ## Proposed `campaign/board.md` rows New row: ``` | THE AI SEED IS PER-PROCESS — tie hypothesis withdrawn, Rung C restated as (save, seed) | meta | verified | high | 100% | 2026-09-08 | Resolver, on lane L1's falsified P7 (`findings/resolutions/2026-09-08-ai-seed-per-process.md`). Each AI StrategyClient's generator is seeded at construction from NextUInt on the global generator at 0x00af6e58, which is LIVE and per-process (three unrelated words per process, none shared across processes; the seed=0 record reproduces byte-identically as the built-in control). OVERTURNED: AI1's "every client seeded with 0" (row 240 second half — its own falsifier row fired; lane H's rejection-loop counter-indication was right) and the coordinator's "one-of-three varies => pointer-ordered tie under ASLR" (rows 331(5)/333, backlog §2) — all three streams move; only 512 reaches the candidate walk (L4). SURVIVES: per-client RNG, zero AI draws on the strategic generator, the ref-turn2 oracle, L5's instrument exoneration (on the identical-hooks pair, NOT on hooks=off), L4's measured facts and k=6 XNC arm. **RUNG C RESTATED: game/ai as a deterministic function of (save, per-client seed)** — C-exact (seeds captured => block and autosave byte-match on EVERY run; the user's "make it deterministic and the old approach pays", literally) and C-set (seeds lost => canonical pick is a member of the nameable outcome set of a random draw, not a tie). ONE PROBE, VM140, minutes: pin the three client seeds in the l1seed Seed detour (ret addr 0x0078304b), turn1-state twice in fresh processes; predict byte-identical, positions 192/211 unchanged; if the four leaves still differ, extend the pin to Seed record #2. Holding => turn1->turn2 with seeds is an oracle again and the ONLY corpus pair exercising BeginProcessTurn's hive draw. OPEN: the global generator has four other consumers incl. RunCombatRound+0x60f — no battle turn has ever been compared across two processes. hooks=off on turn1-state gave THREE different files across L5/L1/L4 and was never a control: rule 25 drafted (a control must agree with itself in two fresh processes; "one of N moved" says nothing about mechanism). L4 corrected mid-flight (draw ledger on client+0x134 at 0x006c8580, pinned-seed runs); CB adds seeds to the capture and a pinned C5; RB adds --ai-seed | ``` Edits to existing rows (the integrator's `SUPERSEDED` convention): - **Row 240** — prefix the notes with: `PARTLY OVERTURNED by lane L1 (resolver 2026-09-08): the per-client RNG and "zero AI draws on the strategic generator" STAND; "never seeded / seeded with 0" is FALSE — the global at 0x00af6e58 is live and per-process. Status back to mapped for the seed half.` - **Row 255** — prefix: `SCOPED: true of ref-turn2 -> turn3 only (no draw-dependent decision that turn); superseded by rows 331 and the resolver row.` - **Row 331** — append: `(5) WITHDRAWN 2026-09-08 — it is a seed, not a tie; see the resolver row.` - **Row 333** — prefix: `RESTATED by the resolver 2026-09-08: the mechanism is a per-process seed, not a tie; the tie-set claim survives only as C-set (fallback for uncaptured seeds); primary Rung C is C-exact given the seed.` - **Row 335** — append: `CB: capture format carries the three AI seeds; add C5 = C3 with pinned seeds, twice. RB: add --ai-seed.` - **Row 62** — VM140 holder: the pin probe, before L4's second capture.