sots-re/findings/control-flow/ai-visit-order-probe.md

610 lines
49 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Is the residual fleet visit order an RNG draw or heap order? — the per-client draw ledger on `ad-turn27`
- **Owner / date:** lane BR · 2026-09-09 · guest **VM146** (`sots-re-win10-146`, `re@192.168.10.146`)
- **Held:** VM146, from the time this prediction was committed. VM140 (reference, exclusive),
VM141 (lane AZ) and VM144 (lane BS) untouched. VM145 free and untouched.
- **Trigger:** `findings/resolutions/2026-09-09-fleet-id-order-residue.md` §4 / §8 — the single probe
the resolver chose over two alternatives, because it is simultaneously **run C** (a third pinned
sample, sizing the residual outcome set) and **probe 3** (the per-client draw ledger).
- **Build:** `bp-989c692-20260909T0505Z`, lane BP's dist, still deployed at `C:\SOTS\shimdist-bp`
(`binkw32.dll` sha256 `9de1c57a38e66800a9487f46f7e7abc4fea6efc05cd72319d911733e9d971f47`).
**No build for this lane** — the resolution costed it at "one fresh process, no build".
- **Input:** `C:\SOTS\SavedGames\ad-turn27-two-raiders.sav`, sha256
`1c8baa27680809d585ab1728391e82729642d32aaedffd5bf95b616f0a11a436`, 100,809 B — **re-verified on
this guest before the run**, equal to lane AD's and lane BP's published value.
- **Route:** **load** (`ad-turn27-two-raiders.sav` → one End Turn), the same route as lane BP's three
runs. This lane holds the route fixed, so it is unconfounded by lane BQ's per-*history* input
(resolution §9.1).
---
## 0. The question, in one paragraph
Lane BP pinned all three AI client seeds on the campaign's richest AI turn and two fresh processes
still disagreed — but only in **35 leaves of 61,147**, and all 35 are a single transposition: two
newly formed fleets exchange contents. The resolver decoded the ids and changed the frame: the ids
are not the variable (1970/1986/2002 are Player[32]'s own client, counters 123/124/125, minted in
that order in every process), the **visit order over the ship groups needing a new fleet** is. Two
mechanisms remain, and only two. **H2:** a draw on the per-process global generator at
`0x00af6e58`, which the seed pin does not touch and which already has two unnamed AI-band consumers
in the record (`0x0079ea90+0x73`, `0x005b9f00+0xc0`). **H1/H1b:** an address-keyed container (or an
unstable comparator) walked in heap order — for which BP's own `aielem` node addresses supply a
*measured precondition* (same-size allocations landing in different relative orders in two processes
with identical decisions), the image base being constant on both guests (lane BQ). This probe
separates them by measurement: `airng=on` brackets each AI client's whole turn at
`StrategyClient::OnResumePlaying` and attributes **every draw on every generator** inside it to a
return address and a generator address. Lane I's inlined-draw inventory places **no** inlined draw
site between `0x680000` and `0x6e0000`, so the observer is complete in the AI band.
---
## 1. Predictions, committed before the run
These are the resolution's §4 **P1–P4**, restated verbatim in substance, with the falsifier of each
named. They are committed in their own commit, with no result in the file.
> **P1 (run C — the outcome set).** `(Autosave).sav` ∈ {`e913ff41188211c02d536da616337544e64133996cd7cc7a6521a8df1960226f`,
> `724528ffde9a7514b69ab9e82ed3b8c8ade63d622c0720de30503a73a92df11e`} — lane BP's A/L file or its B
> file. **A third file does not immediately mean either thing**: it is ambiguous between the order
> outcome set exceeding 2 (`k ≥ 3`) and the `airng` detour perturbing the run. The resolution names
> the disambiguation and this lane will run it if the guest allows: one more run of
> **`shim.cfg.bppin`** (`airng=off`, plain run C). Under the `k ≥ 3` reading that plain run cannot
> land on a *third* distinct file with probability better than 1/3; under the perturbation reading
> it lands on one of BP's two.
>
> **P2 (the headline — probe 3).** In Player[32]'s `OnResumePlaying` bracket:
> `foreign_words=0`, `foreign_calls=0`, `residual=0`, and **no `airngcensus` row whose `rng` is
> anything but Player[32]'s own client generator at `client+0x134`** — in particular none on
> `0x00af6e58` and none on `Seed` record #2's object. The same for clients 496 and 512.
>
> **P3 (the ledger's shape — not load-bearing, recorded so it can be disagreed with).** Player[32]'s
> own generator spends **single-digit words** inside its bracket, at return addresses in the AI band
> (`0x0068xxxx`–`0x006exxxx` RVA-wise, i.e. `va` in `0x0068_0000`–`0x006e_0000` at
> `exe base = 0x005e0000`); clients 496 and 512 spend **fewer** than Player[32].
>
> **P4 (the block).** The `aiorders` dump differs from lane BP's runs A and B **only inside the
> proven noise set** (the L/A mask: list 1 → words 1, 5, 8, 11; list 3 → 4–11; list 5 → 8–11;
> list 7 → 2–11; list 8 → 1–11; list 10 → 2–11; list 12 → 5–11; list 14 → 2–11; list 23 → 2–11) —
> plus, **at most**, the three-word transposition (`list 8 idx=1 word0`, `list 10 idx=0 word0`,
> `list 10 idx=1 word0`). Structure identical: 9 blocks, 81 elements, the same `(pid, list, idx)`
> sequence, the same per-list counts, player 32 emitting `{1:3, 3:19, 5:15, 7:2, 8:3, 10:4, 12:12,
> 14:8, 23:15}`.
### 1.1 How each prediction could be wrong, and the symptom
| way | symptom | what it would mean |
|---|---|---|
| **H2 is right** — some AI-band site draws on the global generator or on another object | ≥ 1 `airngcensus` row with `rng ≠ client+0x134` inside a bracket | **P2 falsified, and that is a success.** The row's `ret_rva`/`va` *names the consumer*. Follow-up is a global pin (`RNG_Seed(0xaf6e58, K)` after `Application::Initialize`), two fresh processes, predict byte-identical. **Stop and post the address.** |
| **H1/H1b is right** | `foreign_words=0` everywhere; the census carries only the client's own generator | **P2 holds.** RNG is excluded *by measurement* for the AI turn, and stage 2 becomes one bounded static read to place a hook on the group walk. **Stop. Do not read the binary. Do not start stage 2.** |
| an **inlined** draw on the AI path that the seven entry-point detours cannot see | `residual > 0` on a bracket (`left_delta > observed`) | P2 falsified in its `residual=0` clause. The residual is a per-generator number measured off the object at `+0x9c8`, so it reports the invisible draw's *existence* without its address; the follow-up would be an image-wide immediate scan restricted to the AI band, which lane I already ran and which found nothing there — so this outcome would also contradict lane I. |
| the **`airng` detour perturbs the turn** (rule 19) | a third autosave file | Not separable from `k ≥ 3` by this run alone — see P1. **This is the caution the resolver put on the record and it will be reported as ambiguity, not resolved by preference.** The disambiguation is one plain `shim.cfg.bppin` run. |
| the pin is **half-applied** | any `aiseed call=… pinned=0`, or a `PIN MODE WITH NO PINS` line, or a `used=deadbeef` wildcard hit | The run is **void** and nothing is read from it. Checked in `shim.log` *before* any output file is opened. |
| a **stale or wrong binary** (rule 24) | `BUILD_ID` ≠ `bp-989c692-20260909T0505Z` in `shim.log` | Void. No build is done by this lane, so the only failure mode is deploying the wrong dist. |
| the **config** carries an inherited defect | a live line inside what was meant to be a comment; an unnamed registered hook silently installed | Defended by the check that caught it in BP's own first draft: **the non-comment diff of `shim.cfg.bppin` against `shim.cfg.brprobe`, quoted in §2.1**, must be exactly three lines. |
| the **click path** lands somewhere else | wrong screen in a screenshot | Every step screenshotted and verified; never sleep-and-click. And the wall's `/shot/<id>.png` is a **cached frame up to ~5 s stale** (BP's gotcha, four wasted clicks) — wait 12–16 s or take two shots and use the second. |
### 1.2 What this probe cannot decide, whatever it says
It is one save, one procedure, one build, one route (**load**), and — for the ledger half — the
turn's *own* AI band. A `foreign_words=0` result excludes a draw **inside the bracket**; it says
nothing about a draw taken before `OnResumePlaying` is entered whose value is carried into the
visit order (nothing in the record proposes such a path, and the seed pin is applied earlier still,
at `RunAI`, so a pre-bracket draw would have to be on a generator the pin does not touch and be
consumed later — named here so nobody reads P2 holding as more than it is). It also cannot identify
the container: that is stage 2's hook, and the resolver was explicit that the read must not begin
before this probe returns. The 3–40-turn fuse at `0x0069dbb0` cannot fire inside one turn of a load
and is untested here, exactly as in lane BP.
---
## 2. The procedure
### 2.1 The config, and the non-comment diff (the check this lane was briefed to run)
`shim.cfg.brprobe` is `shim.cfg.bppin` with **exactly three non-comment lines changed**. Diffed
twice, once on the host before the file was pushed and once **on the guest, from the two files that
were actually there**:
```
$ diff <(grep -v '^\s*#' shim.cfg.bppin | grep -v '^\s*$') \
<(grep -v '^\s*#' shim.cfg.brprobe | grep -v '^\s*$')
6c6,8
< airng=off
---
> airng=on
> airng.pin_seed=off
> airng.out=C:\SOTS\shim.airng.txt
```
`bppin` has 43 live lines, `brprobe` 45. Everything else — `hooks=trace`, all **28** registered
hooks off *by name*, `aiorders=on` with `deep=off` and `words=12`, `aiprobes=off`,
`airesearch=off`, `aiseed=pin` with `32=156ebbbd,496=fe7b2826,512=0ed341d1,*=deadbeef` — is
byte-for-byte BP's. `airng.pin_seed=off` is stated explicitly even though it is the default: a
pinned generator is a declared perturbation and the resolution forbids it here, so it is written
down rather than assumed.
The same diff, taken **from the runtime `config:` lines of the two `shim.log`s** rather than from
the files, is identical — an independent confirmation that the three lines are the three lines that
reached the process:
```
$ diff <(grep -o 'config: .*' bp/A-shim.log) <(grep -o 'config: .*' br/BR-shim.log)
6c6,8
< config: airng=off
---
> config: airng=on
> config: airng.pin_seed=off
> config: airng.out=C:\SOTS\shim.airng.txt
```
BP's report says its own first draft of a config reproduced an inherited defect (a wrapped header
comment leaving a live line in the body) and that this diff is what caught it. This lane's inserted
header is seven lines, every one `#`-prefixed; the 45 live lines were printed and read before the
run.
### 2.2 The instrument, verified from `shim.log` before anything was read
* `build bp-989c692-20260909T0505Z` — BP's dist, unmodified, no build by this lane;
`binkw32.dll` sha256 `9de1c57a…d971f47`.
* `exe base=0x005e0000 (link-time image base 0x00400000, ASLR delta +1966080) pid=7064` — the
same base lane BQ measured in three of BP's processes on this guest, so **image base is constant
here for a fifth time** and "pointer order" can still only mean heap order.
* **27** `hook: … mode=off (not installed)` lines plus `selftest: … mode=off` = **28 of 28**
registered hooks off. **Zero** `ignoring unknown key`. **Zero** `COVERAGE:`.
* seven `drawsite:` detours `create=MH_OK enable=MH_OK`;
`aiorders: … probes=0 of 20`; `aicfg words=12 deep=0 research=0 seed=pin pins=4 detours=2`;
one batch detour `MH_OK`; one `aiseed` detour `MH_OK`.
* **the two lines the brief names**:
```
airng: bracket StrategyClient::OnResumePlaying rva=0x00377480 va=00957480 create=MH_OK enable=MH_OK
airng: out=C:\SOTS\shim.airng.txt pin_seed=off:00000000
airng: facade cl_Chance rva=0x00178cf0 va=00758cf0 create=MH_OK enable=MH_OK
airng: facade cl_RandRange rva=0x001798e0 va=007598e0 create=MH_OK enable=MH_OK
```
No `airng: PINNING IS ON` line, as required.
* **the pin, three of three**, and no `PIN MODE WITH NO PINS`, no `pinned=0`, no wildcard hit:
```
aiseed call=1 netId=32 observed=0xd0598a7d used=0x156ebbbd pinned=1
aiseed call=2 netId=496 observed=0x91193aec used=0xfe7b2826 pinned=1
aiseed call=3 netId=512 observed=0x9733ed32 used=0x0ed341d1 pinned=1
```
Three new natural seeds, shared with none of BP's nine — **lane L1's per-process seeding
reproduced a fifth time**, now on a turn-27 state.
### 2.3 Standing instruction: who actually runs, and by which route
* **`RunAI` net-id list: 32 / 496 / 512** — three AI clients, in that order, exactly as lane BP
measured. The save's other four non-human players (528 Alien Menace, 544 Peacekeeper Enforcer,
560 Von Neumann, 576 Independent Colony) get no client, no call and no seed. Independently
confirmed a second way this run: the `airng` bracket fired **five** times — `pid=16` (human,
`agent=0x00000000`) at load, then `pid=32`, `pid=496`, `pid=512` each with a non-null agent, then
`pid=16` again — and never for 528–576.
* **Route: load.** `ad-turn27-two-raiders.sav` → Load Game → Single Player → OK → row 1 (400,260)
→ OK → Launch → one End Turn. No continuation. Every dialog step verified from a fresh QEMU
screendump (`screendump -f png` over the guest's QMP socket, which bypasses the lab wall's
~5 s frame cache entirely — see §5).
* **Exposure** (rule 26 (c), unchanged from BP and re-derived from this run's own outputs):
Player[32] enters with `ResTNm = BIO_TerBac` **held**, `NumDes` 46, `NumOwn` 15, **13 ships
completing into new fleets**; 496 and 512 hold targets with `NumOwn = 0`; the four NPC factions
have `ResTNm == ''` and no client. Exposed on the design, fleet-assignment and colony counts, not
on the research pick. **No encounter query** — End Turn ran straight to the post-turn autosave.
Timings on this guest, for the next lane: `schtasks /Run /TN SOTS` → `fg` + `key {ESC}` ×3 spaced
2.5 s → **main menu at ~2 min 45 s** (screenshot-verified, never slept-and-clicked); the click path
through the Load dialog ~2 min at one click per helper call; **the turn-27 load 3 min 20 s** the
first time and **1 min 55 s** the second; **End Turn ~4 s** with this hook set — BP's "~35 s" is
generous, and the autosave mtime is the reliable completion signal.
---
## 3. The result
### 3.0 Lead
**P1 holds, P2 holds, P4 holds, P3 is falsified in its stated form.** There is **no foreign
draw** — not one word, in any of the three AI clients' brackets. And the ledger says something
sharper than "none": over the **entire process lifetime**, the per-process global generator at
`0x00af6e58` was drawn **exactly three times, three words, from exactly one return address**, and
that address sits **16 bytes before the `RunAI` call site** — it is the AI client seed mint itself,
one draw per client, the thing the pin overwrites. **RNG is excluded by measurement. H2 is dead.**
A second run followed (§4.2, the Rung B record) and landed on the **other** branch, which makes the
outcome set two-for-two: **five processes on this state, three on `e913ff41…`, two on
`724528ff…`, no third file.**
### 3.1 P1 — the autosave, and which file it is
| | file | sha256 | bytes |
|---|---|---|---|
| pre-turn | `(Autosave EndTurn).sav` | `16f63adbf383946db17c381998957172bca803406b7df78f3b03805fef0bbcb8` | 100,758 |
| **post-turn** | `(Autosave).sav` | **`e913ff41188211c02d536da616337544e64133996cd7cc7a6521a8df1960226f`** | 101,375 |
**It equals `e913ff41…` — lane BP's run A, which is also lane BP's run L.** Not a third file, so the
resolver's ambiguity caution does not fire and no disambiguation run was needed on that account.
`state_checksum.py --floats bits --mask none`:
* post-turn **BR vs `bp-pinA-turn28.sav`: `IDENTICAL`**, root `8100b28960f729ef9a24a22f13397b4a` —
the same root BP recorded for L and A;
* post-turn **BR vs `bp-pinB-turn28.sav`: `DIVERGED: 35 leaf difference(s)`**, and the 35 are
BP's transposition, leaf for leaf (`Flt[1970]`/`Flt[1986]` exchanging `Pos`, `PrvPos`, `FtOrig`,
`FPlan`, `LocID` 384↔0, `HFPlan`, `FtTrans`, `FtFlg` 12↔13, `Ship[6976]`↔`Ship[5264]`, plus
`Sys[384]/Flt[1]`, `ShipIDs[]` list-reordered and `Summary/Checksum`). Nothing else moved;
* pre-turn **BR vs `bp-turn28-pre.sav`: `IDENTICAL`**, root `6bbaf382c9e570ae882b599f566ae62e`.
**This is also the instrument's own control, in rule 26 (d)'s shape.** The `airng` detour cannot be
removed and cannot be argued away; what it *can* do is reproduce a natural run. It did:
a process carrying the `OnResumePlaying` bracket and two facade detours wrote the same bytes as
lane BP's unpinned run L. `airng`'s behavioural neutrality was previously an argument from
`roll-parity.md`; on **this** state it is now a measurement.
### 3.2 P2 — the per-client draw ledger. The bracket rows, all five
```
airng seq=1 pid=16 agent=0x00000000 rng=0x0d820d18 pin=off left=624->624 idx=0->0 left_delta=0 observed=0 calls=0 residual=0 foreign_words=0 foreign_calls=0 sites=0 overflow=0 life_in=0 life_out=0
airng seq=2 pid=32 agent=0x327811e0 rng=0x33a90010 pin=off left=612->533 idx=12->91 left_delta=79 observed=79 calls=75 residual=0 foreign_words=0 foreign_calls=0 sites=4 overflow=0 life_in=12 life_out=91
airng seq=3 pid=496 agent=0x32780038 rng=0x1f324540 pin=off left=219->219 idx=405->405 left_delta=0 observed=0 calls=0 residual=0 foreign_words=0 foreign_calls=0 sites=0 overflow=0 life_in=405 life_out=405
airng seq=4 pid=512 agent=0x32780ad0 rng=0x33968010 pin=off left=206->206 idx=418->418 left_delta=0 observed=0 calls=0 residual=0 foreign_words=0 foreign_calls=0 sites=0 overflow=0 life_in=418 life_out=418
airng seq=5 pid=16 agent=0x00000000 rng=0x0d820d18 pin=off left=624->624 idx=0->0 left_delta=0 observed=0 calls=0 residual=0 foreign_words=0 foreign_calls=0 sites=0 overflow=0 life_in=0 life_out=0
```
**`foreign_words=0 foreign_calls=0 residual=0` in every bracket, including the one that matters.**
`left_delta == observed` on Player[32] (79 = 79), so the two independent measurements agree and
there is **no inlined draw** on the AI path either — which is what lane I's inventory predicted and
what a call-graph-shaped observer could not have asserted on its own.
The four in-bracket sites for Player[32], by return address (`va` in these rows is the **Ghidra**
VA, `0x00400000 + rva`, not the runtime VA the install lines print):
| `ret_rva` | Ghidra `va` | entry | calls | words |
|---|---|---|---:|---:|
| `0x004e6e09` | `0x008e6e09` | NextFloat | 10 | 0 |
| `0x00178d15` | `0x00578d15` | Chance | 10 | 10 |
| `0x002ad878` | `0x006ad878` | NextFloat | 22 | 22 |
| `0x00179915` | `0x00579915` | NextInt | 43 | 47 |
and the facade call sites, all six in the AI band `0x0068–0x006e`: `cl_Chance` from `0x0069086f`
(2 calls), `0x006adf35` (2), `0x006adfca` (3, **2 true**), `0x006ae418` (3); `cl_RandRange` from
`0x006ad94c` (22) and `0x00691ea0` (21).
### 3.3 The census rows whose generator is not that client's own — and the one that matters
The `airngcensus` table is a **whole-process lifetime** ledger (its per-generator totals are the
`airngen life_words`, and rows for clients 496/512 are already present at `seq=2`, before those
brackets ran). So "foreign rows" here means *rows on a generator other than the bracket's own*,
and the bracket row's `foreign_words=0` is what says none of them moved **inside** the bracket. Five
generators were seen in the whole run:
| runtime `rng` | what it is | lifetime words |
|---|---|---:|
| `0x00cd6e58` | **the per-process global generator — static `0x00af6e58`** (runtime = static + the `0x1e0000` ASLR delta) | **3** |
| `0x33a90010` | Player[32]'s client generator (the word at `client+0x134`) | 91 → 94 |
| `0x1f324540` | client 496's | 405 → 407 |
| `0x33968010` | client 512's | 418 → 420 |
| `0x0d820d18` | human client 16's | 0 |
| `0x0d83b170` | a server-side generator, first seen at `seq=5` (post-AI) | 20 |
**The whole of the global generator's activity, every row it has in the file, at every seq from 2
to 5:**
```
airngen seq=2..5 rng=0x00cd6e58 life_words=3 life_calls=3
airngcensus seq=2 rng=0x00cd6e58 ret_rva=0x00384f9e va=0x00784f9e entry=NextUInt calls=3 words=3
airngcensus seq=5 rng=0x00cd6e58 ret_rva=0x00384f9e va=0x00784f9e entry=NextUInt calls=3 words=3
```
**Three calls, three words, one return address, and the count does not move between the first AI
bracket and the end of the turn.** The two AI-band consumers the resolution named as candidates —
`0x0079ea90+0x73` (`RNG_Chance`) and `0x005b9f00+0xc0` — appear **nowhere** in the census: they did
not fire in this process at all.
**What `0x00784f9e` is** — inference from the record, not from the binary, which this lane was told
not to read. Lane AI1 records that `StrategyApp::RunAI` is "reached only from
`StrategyNetworkClient::OnMessage 0x00784640 + 0x96e`", i.e. the call is at **`0x00784fae`**. The
return address of the only global-generator draw in the process is **`0x00784f9e`, sixteen bytes
earlier, in the same function**, and it fires **exactly three times for exactly three AI clients**,
at 02:30:34 — the same log timestamps as the three `aiseed call=…` lines. That is the seed mint:
board row 326's "one 32-bit word drawn per AI client at construction from a per-process global",
now measured live, with its consumer's address, its generator's address and its call count. It is
also the *only* thing that generator does. A one-line static read would confirm the instruction;
this lane did not take it.
### 3.4 P3 — falsified, as the weak prediction it was labelled
P3 said Player[32] would spend **single-digit** words in its bracket. It spent **79** (75 calls,
four sites). The second half — "496 and 512 spend fewer" — holds degenerately: they spend **zero**.
Recording it because rule 2 says a prediction exists to be disagreed with, and this is exactly rule
23's corollary again: a bracket total is a sum over every subsystem inside it, and this one was
guessed rather than modelled.
Two things in the ledger are worth more than the number:
* **Clients 496 and 512 run a full AI turn and draw nothing.** `left` does not move, `idx` does not
move, `agent` is non-null. Rule 20's design working: "ran and drew nothing" is visibly different
from "never ran". Their 405 / 418 lifetime words were all spent **before** the bracket, at client
construction.
* **The 3–40-turn fuse consumer `0x0069dbb0` DID draw — before the bracket, on each client's own
(pinned) generator.** Census rows `0x0069dc02` (= `+0x52`) and `0x0069dc2e` (= `+0x7e`): 2+1
words for client 32, 1+1 for 496, 1+1 for 512, all inside `life_in`. Both lane BP and lane BQ
recorded that this fuse "cannot fire inside one turn of a load and is therefore untested"; that
is right about the *turn*, and this run shows the site is nevertheless **entered on the load path**
(`RunAI` → `RaiseAIPrepareTurn`), on the seeded generator. Rule 28 practice 4 exactly: an entry is
not a cost, and a zero in a bracket is not a statement about the subtree.
### 3.5 P4 — the `aiorders` diff against BP's runs A and B, under BP's noise mask
Mask = the `(list, word)` positions BP's byte-identical L/A pair **proves** cannot be read by the
applier (list 1 → 1, 5, 8, 11; list 3 → 4–11; list 5 → 8–11; list 7 → 2–11; list 8 → 1–11;
list 10 → 2–11; list 12 → 5–11; list 14 → 2–11; list 23 → 2–11), plus — named by BP in the same
section and separated out explicitly here — **`aiblk` gate payloads whose SET flag is 0**, which are
lane L4's uninitialised-when-unset words.
The comparator was self-tested against BP's own published result before being pointed at this run:
on `A vs B` it reproduces §3.4's three words and nothing else; on `L vs A` (the pair that *defines*
the mask) it reports NONE. Full output in `verify/results/shim/br/aiorders-diff.txt`.
**BR vs run A** — 9 blocks, 81 elements, identical `(pid, list, idx)` key sets, identical per-list
sizes (`{1:3, 3:19, 5:15, 7:2, 8:3, 10:4, 12:12, 14:8, 23:15}` for pid 32), identical **set** gates
(`rate=1:1` for pid 16, `rate=1:0.8` for 32/496/512):
```
== word diffs, masked ==
NONE. Every differing word is inside the proven noise set.
```
**BR vs run B** — same structure, and **exactly the three transposition words**:
```
blk=1 pid=32 list= 8 idx=1 word0 B=0x000007b2 (1970) BR=0x000007c2 (1986)
blk=1 pid=32 list=10 idx=0 word0 B=0x00000050 (80) BR=0x00000180 (384)
blk=1 pid=32 list=10 idx=1 word0 B=0x00000180 (384) BR=0x00000050 (80)
```
The visit order, read straight off list 10 as the resolution says it can be:
```
L : (384,1970) (80,1986) (384,2002) (816,7072)
A : (384,1970) (80,1986) (384,2002) (816,7072)
BR: (384,1970) (80,1986) (384,2002) (816,7072) <- system 384 visited first
B : (80,1970) (384,1986) (384,2002) (816,7072) <- system 80 visited first
```
**P4 holds in its strong form**: the difference from A is empty, and the difference from B is the
transposition and nothing else.
### 3.6 A free measurement the dumps already contained: heap order does not track visit order
The resolution's §2.2 read node heap addresses out of BP's `aielem` rows to show that same-size
allocations land in different relative orders in two processes. The same rows in this lane's two
runs extend that, and add one negative result that matters for stage 2.
Player[32]'s list 3 — nineteen nodes allocated in one pass — low 16 bits of the first eight, in
emission order, across **four** processes:
| run | visit order | first eight list-3 node addresses |
|---|---|---|
| L | 384 first | `6338 6238 6358 6378 6418 64b8 63b8 6458` |
| A | 384 first | `f838 f538 f898 f4f8 f518 fa38 fc98 0378` |
| BR | 384 first | `2f78 2df8 3038 3018 3078 2cd8 3a78 c458` |
| B | 80 first | `e1c0 e320 e200 e380 e460 e500 e260 e4e0` |
Four processes, four different relative orders, for an allocation sequence that is identical
(identical decisions, identical block structure). **§2.2's precondition is reproduced on four
processes, and L vs A shows it holds even between two processes whose autosaves are byte-identical.**
And the negative: the emitted **command nodes'** relative address order does **not** track the visit
order. For list 10's four elements, `idx1 < idx0` in BR and in B (different visit orders) and
`idx1 > idx0` in A and in L (same visit order as BR). So you cannot read the visit order off the
block's own node addresses — which is expected, since those nodes are allocated *after* the visit
decision, but it is worth stating because it closes the cheapest imaginable shortcut. **Stage 2 must
hook the walked container; the dump cannot substitute for it.**
---
## 4. Verdict
### 4.1 Which hypothesis survives
> **H2 — "a foreign RNG draw sets the visit order" — is DEAD, by measurement.**
>
> Zero foreign words and zero foreign calls in all three AI clients' brackets; `residual = 0`, so
> not an inlined draw either; and the per-process global generator at `0x00af6e58` was touched
> **three times in the entire process**, all three at one return address `0x00784f9e` inside
> `StrategyNetworkClient::OnMessage`, sixteen bytes before the `RunAI` call — one seed per AI
> client, which is precisely the word the pin overwrites. Neither of the two unnamed AI-band
> consumers the resolution named fired at all.
>
> **H1 / H1b — an address-keyed container, or a comparator reading an uninitialised word, on the
> fleet-assignment path — is the only hypothesis left standing**, and this run neither confirms nor
> distinguishes them. It does strengthen their shared precondition to four processes (§3.6) and it
> rules out reading the answer off the block (§3.6).
Per the brief, this lane **stops here**. The binary was not read and stage 2 was not started. The
follow-up the resolution names is now unblocked and unchanged: one bounded static read of
`AssignFleetsAndIssueOrders 0x006c16c0` and the gathering hub *to place a hook* on the loop that
visits the ship groups, logging `(element address, systemId, minted fleetId)` in visit order, two
fresh processes. Under H1 the visit order equals ascending element address in both and the two
processes' address orders differ exactly where their visit orders differ; under H1b it tracks
neither.
**On the caution the resolver put on the record:** it does not apply. The probe run produced BP's
`e913ff41…`, not a third file, so this lane is in neither the `k ≥ 3` case nor the
instrument-perturbation case; and the second run (§4.2) produced BP's `724528ff…`. The disambiguation
run was therefore not needed and was not performed. **No pinned file was compared with any of lane
AD's unpinned files.**
### 4.2 The Rung B record — run 2, taken while the guest was warm
Config `shim.cfg.brdeep` = `shim.cfg.bppin` with **one** non-comment line changed
(`aiorders.deep=off` → `on`); `airng` stays `off`, which is bppin's own value. Verified in the log:
`aicfg words=12 deep=1 research=0 seed=pin pins=4 detours=2`, three `pinned=1`, no `airng:` lines,
no unknown keys.
**Hash:** `(Autosave).sav` = **`724528ffde9a7514b69ab9e82ed3b8c8ade63d622c0720de30503a73a92df11e`**,
101,370 B — **byte-identical to lane BP's run B**, verified with `cmp`. Pre-turn autosave
`16f63adb…` as always. So the resolution's stated target ("if it lands on `e913ff41…`") was **not**
hit; it landed on the other branch. **That does not cost the record anything**, and §6's own logic
is why: the residual input is *written into the block*, so the record is complete as
`(ad-turn27-two-raiders.sav, load → one End Turn, seeds 32=156ebbbd / 496=fe7b2826 / 512=0ed341d1,
visit order = list 10's order in the captured deep block, deep block, → 724528ff…)`. It is the
campaign's **first replayable rich-turn record** — thirteen ships completing, a design created, a
system colonised — and it is on the branch that lane BP's `bp-pinB-turn28.sav` already holds.
**Does the deep dump follow list 10's ship vectors and list 8's routes?** Yes, both, and list 1's
strings as well:
```
aistr blk=1 pid=32 list=1 idx=0 at=w2 sso=1 len=14 text="Egg Thief Mk 4"
aistr blk=1 pid=32 list=1 idx=1 at=w2 sso=1 len=14 text="Egg Thief Mk 5"
aistr blk=1 pid=32 list=1 idx=2 at=w2 sso=1 len=14 text="Bravestar Mk 3"
ailist blk=1 pid=32 list=8 size=3
aielem ... list=8 idx=0 ints=[ 2002 ... ] aivec ... at=w1 cap=1 count=1 ints=[ 256 ]
aielem ... list=8 idx=1 ints=[ 1970 ... ] aivec ... at=w1 cap=1 count=1 ints=[ 384 ]
aielem ... list=8 idx=2 ints=[ 1538 ... ] aivec ... at=w1 cap=1 count=1 ints=[ 240 ]
ailist blk=1 pid=32 list=10 size=4
aielem ... list=10 idx=0 ints=[ 80 1970 ... ] aivec ... at=w2 cap=1 count=1 ints=[ 5264 ]
aielem ... list=10 idx=1 ints=[ 384 1986 ... ] aivec ... at=w2 cap=1 count=1 ints=[ 6976 ]
aielem ... list=10 idx=2 ints=[ 384 2002 ... ] aivec ... at=w2 cap=1 count=1 ints=[ 6992 ]
aielem ... list=10 idx=3 ints=[ 816 7072 ... ] aivec ... at=w2 cap=11 count=11 ints=[ 2992 3456 4304 4912 5680 3184 5856 6000 6256 6464 2720 ]
```
35 `aivec` rows and 3 `aistr` rows across the block; list 3 and list 12 carry their vectors too
(list 12's twelve elements resolve 3, 15, 1, 5, 4, 6, 20, 22, 11, 7, 1 and 7 ship ids). Under the
noise mask the deep run's shallow words are **element-for-element identical to BP's run B**, so
`deep=on` is confirmed to be additive: it adds followed rows, it does not disturb the block.
**Two cross-checks the deep dump makes possible for the first time, both pass.** (1) The block's
ship↔fleet pairing matches the save it produced: in this run list 10 gives fleet **1970 ← ship 5264**
at system 80 and fleet **1986 ← ship 6976** at system 384, and `bp-pinB-turn28.sav` is exactly the
save in which `Flt[1970]` holds `Ship[5264]`. The resolution's "the visit order is written into the
block" is now verified end to end, block → save. (2) **The move goes to the group at system 80 in
both orders**: list 8 idx=1 is fleet 1970 with route `[384]` here, and fleet 1986 with the same
route in run A — and 1970-here and 1986-there are both the system-80 group. That is the resolution's
§3 qualification ("on `ad-turn27` the move in list 8 went to the group at system 80 in both orders")
confirmed from the command stream rather than inferred.
### 4.3 The outcome set, after five processes
| file | processes | visit order |
|---|---|---|
| `e913ff41…` | **3** — BP's L (unpinned), BP's A (pinned), BR's probe (pinned + `airng`) | 384 first |
| `724528ff…` | **2** — BP's B (pinned), BR's deep (pinned + `deep`) | 80 first |
**No third file in five processes.** The outcome set is still observed at 2, now with both members
reproduced at least twice and across three different instrument configurations. That is not a proof
that `k = 2` — a binary order over two groups makes 2 the natural size, but nothing here rules out a
turn where more groups make it larger — and it is enough to say the residue is a small,
enumerable order rather than an unbounded scramble, which is what C-set's shape needs.
### 4.4 What this lane did NOT establish
* Nothing about a draw taken **before** `OnResumePlaying` is entered whose value is carried into the
visit order. The bracket is an exact bracket around the turn, not around the client's life. The
global generator's constancy (3 words, lifetime, one site) is what actually closes that door, and
it closes it for *that* generator only.
* Nothing about the container's identity. §3.6 shows the block cannot tell you.
* Nothing about a turn other than this one, a route other than load, or a build other than
`bp-989c692`.
* The `0x0069dbb0` fuse's *turn-time* behaviour remains untested (it fired on the load path here,
which is a different statement).
* The `0x00784f9e` attribution is an **inference** from lane AI1's recorded call-site offset plus a
count that matches the client count exactly. It is one instruction away from being a measurement
and this lane did not take that step, by instruction.
---
## 5. Guest notes for the next lane (VM146)
* **The lab wall's cached frame was avoided entirely, and there is a better instrument.** A direct
QEMU screendump — `echo 'screendump /tmp/x.png -f png' | qm monitor 146` on spicy, then `scp` —
returns the **live** framebuffer with no poll cycle in it. Twelve screenshots this session, zero
ambiguous frames, zero wasted clicks. BP's "wait 12–16 s" is the right advice for `/shot/<id>.png`
and is unnecessary if you take the screendump yourself. (`tools/vmshot.py` cannot be used from
this host: it imports PIL and PIL is not installed here.)
* **`bpshot.ps1` reads `C:\SOTS\ui\log.txt` after a 3-second sleep, and the click-helper task writes
that file at the END of its batch.** So for any batch longer than ~3 s the log you get back is the
*previous* batch's — it printed a timestamp 37 minutes stale on my first call. Harmless once you
know; read the log in a separate call, or ignore it and screenshot.
* Load-dialog geometry **confirmed unchanged**: with the two autosaves deleted the list is 7 rows
from y=260 at 29 px pitch and `ad-turn27-two-raiders` is **row 1 at (400,260)**. Path:
Load Game (512,536) → Single Player (512,290) → OK (551,523) → row (400,260) → OK (682,624) →
Launch (511,663) → End Turn (100,714). One click per helper call.
* Timings, both runs (§2.3): main menu ~2 min 45 s; turn-27 load 3 min 20 s then 1 min 55 s;
**End Turn ~4 s**.
* **Released restored**, hash-verified: `SavedGames` back to the 9-file pre-BR set with both
autosaves byte-identical to `C:\SOTS\ui\preBP\` (`a3f9dc4b…`, `d59bb9f2…`), `shim.cfg` =
`hooks=off`, `binkw32.dll` = `07c962946d93c2cfef336803ac041150bda2640c05980b266902b1aa1a618359`
(the pre-BP file), `shim.trace.jsonl` removed, game process **not running** — exactly as found.
Left in place: `C:\SOTS\shimdist-bp\shim.cfg.brprobe` and `shim.cfg.brdeep`, and
`C:\SOTS\ui\br-probe-turn28{,-pre}.sav`, `br-deep-turn28.sav`, `br1-{airng,aiorders,shim.log}`,
`br2-{aiorders,shim.log}`. `click_helper.ps1`, `bpdeploy.ps1`, `bpshot.ps1`, `bphash.ps1`
untouched.
**Artefacts:** `verify/results/shim/br/` — `BR-shim.log`, `BR-airng.txt`, `BR-aiorders.txt`,
`BR2-shim.log`, `BR2-deep-aiorders.txt`, `aiorders-diff.txt` (all four comparisons including the two
self-tests), `cmp_aiorders.py` (the masked comparator), `shim.cfg.brprobe`, `shim.cfg.brdeep`. The
two output saves are **byte-identical to `verify/results/saves/bp-pinA-turn28.sav` and
`bp-pinB-turn28.sav`** and are deliberately **not** duplicated in the repo.
---
## Proposed board rows
New row:
```
| RNG IS EXCLUDED BY MEASUREMENT FOR THE AI VISIT ORDER - the global generator is drawn THREE TIMES IN A PROCESS, all three to mint the AI client seeds | control-flow | verified | high | 100% | 2026-09-09 | Lane BR, VM146, the single probe of `findings/resolutions/2026-09-09-fleet-id-order-residue.md` section 4 (`findings/control-flow/ai-visit-order-probe.md`). No build: lane BP's dist `bp-989c692-20260909T0505Z`, `shim.cfg.brprobe` = `shim.cfg.bppin` with EXACTLY THREE non-comment lines changed (`airng=on`, `airng.pin_seed=off`, `airng.out=`), diffed twice - once file-to-file on the guest, once from the two runs' runtime `config:` lines, both giving the same three lines. 28 of 28 registered hooks off BY NAME, zero unknown keys, zero COVERAGE lines, `aiseed call=1/2/3 pinned=1`, no wildcard hit, `airng: bracket ... MH_OK` + `pin_seed=off`. Route: LOAD. RunAI net-id list: 32/496/512 (three clients; the four NPC factions get none) - confirmed a second way by the bracket firing 5x (pid 16 human agent=0, then 32/496/512 with agents, then 16). **P1 HOLDS: `(Autosave).sav` = `e913ff41...`, BYTE-IDENTICAL to lane BP's runs A and L** (state_checksum IDENTICAL, root 8100b289..., 61147 leaves; vs BP's B, the same 35-leaf transposition, leaf for leaf; pre-turn `16f63adb...` IDENTICAL). Not a third file, so the resolver's ambiguity caution does not fire - AND this is the airng detour's own rule-26(d) control: an instrumented process reproduced an unpinned natural run byte for byte, so `airng`'s behavioural neutrality is now MEASURED on this state, not argued from roll-parity.md. **P2 HOLDS, AND HARDER THAN PREDICTED. `foreign_words=0 foreign_calls=0 residual=0` in ALL THREE AI brackets** (pid 32: left_delta=79 observed=79 calls=75 sites=4; pid 496 and pid 512: left_delta=0, observed=0 - they run a full AI turn and DRAW NOTHING, rule 20's design working). left_delta == observed on pid 32 so there is NO INLINED DRAW on the AI path either, confirming lane I's inventory from the other side. **AND THE LIFETIME CENSUS CLOSES IT: the per-process global generator 0x00af6e58 (runtime 0x00cd6e58) was drawn EXACTLY 3 TIMES, 3 WORDS, FROM ONE RETURN ADDRESS, `va=0x00784f9e`, entry NextUInt - and the count is 3 at every seq from 2 to 5, i.e. it does not move during the turn at all.** `0x00784f9e` is INSIDE `StrategyNetworkClient::OnMessage 0x00784640` and sits 16 BYTES BEFORE the `RunAI` call site that lane AI1 recorded at OnMessage+0x96e = 0x00784fae, and it fires exactly three times for exactly three AI clients at the same log timestamps as the three `aiseed call=` lines: **it is the AI client seed mint - board row 326's mechanism, measured live with its consumer address, generator address and call count, and it is the ONLY thing that generator does in the whole process.** (Inference on the identification, one instruction from a measurement; this lane was instructed not to read the binary.) The two unnamed AI-band consumers the resolution named as H2 candidates (0x0079ea90+0x73, 0x005b9f00+0xc0) DO NOT APPEAR IN THE CENSUS AT ALL. **VERDICT: H2 IS DEAD. H1/H1b (an address-keyed container or an uninitialised-word comparator on the fleet-assignment path) IS THE ONLY HYPOTHESIS LEFT.** **P4 HOLDS in its strong form**: under BP's L/A-proven noise mask (plus unset `aiblk` gate payloads, lane L4's class), BR vs run A = 9 blocks / 81 elements / identical key sets / identical per-list sizes / identical SET gates and **NOT ONE differing word outside the noise set**; BR vs run B = **EXACTLY the three transposition words** (list 8 idx1 w0 1986/1970, list 10 idx0 w0 384/80, list 10 idx1 w0 80/384). The comparator was self-tested against BP's published A/B and L/A results first. **P3 FALSIFIED** (it was labelled not load-bearing): pid 32 spent 79 words, not single digits - rule 23's corollary again, a bracket total is a sum over every subsystem in it. INCIDENTAL, and it is a rule-28 practice-4 case: **the 3-40-turn fuse consumer 0x0069dbb0 DOES draw - on the LOAD path, before the bracket, on each client's own (pinned) generator** (census 0x0069dc02 and 0x0069dc2e: 2+1 words for client 32, 1+1 for 496 and 512, all inside life_in). Its turn-time behaviour is still untested. FREE MEASUREMENT FROM THE DUMPS: section 2.2's LFH precondition now holds on FOUR processes (list-3 node addresses in four different relative orders for an identical allocation sequence - including between L and A, whose autosaves are byte-identical), AND a negative that matters for stage 2 - **the emitted command nodes' relative address order does NOT track the visit order** (BR and A share a visit order and differ in node order; BR and B share a node order and differ in visit order), so the block cannot substitute for the container hook. NEXT (unchanged, now unblocked): one bounded static read of AssignFleetsAndIssueOrders 0x006c16c0 + the gathering hub TO PLACE A HOOK on the group walk, log (element addr, systemId, minted id) in visit order, x2 processes. Artefacts: `verify/results/shim/br/` |
```
```
| THE FIRST REPLAYABLE RICH-TURN RECORD - a deep AI command block for ad-turn27, on the 80-first branch | control-flow | verified | high | 100% | 2026-09-09 | Lane BR run 2, VM146, the Rung B record of `findings/resolutions/2026-09-09-fleet-id-order-residue.md` section 6 (`findings/control-flow/ai-visit-order-probe.md` section 4.2). `shim.cfg.brdeep` = `shim.cfg.bppin` with ONE non-comment line changed (`aiorders.deep=off` -> `on`); `airng` stays off. Verified: `aicfg words=12 deep=1 research=0 seed=pin pins=4 detours=2`, three `pinned=1`, zero unknown keys. **The record: (`ad-turn27-two-raiders.sav` 1c8baa27..., LOAD -> one End Turn, seeds 32=156ebbbd/496=fe7b2826/512=0ed341d1, build bp-989c692-20260909T0505Z, visit order = list 10's order in the captured block) -> pre `16f63adb...`, post `724528ffde9a7514b69ab9e82ed3b8c8ade63d622c0720de30503a73a92df11e`** - BYTE-IDENTICAL to lane BP's run B (`cmp`, not just the hash). The resolution's stated target was `e913ff41...`; it landed on the OTHER branch and **that costs the record nothing**, because the residual input is written into the block (section 6's own logic): list 10 records the visit order on every captured run. THE DEEP DUMP FOLLOWS EVERYTHING IT WAS SUPPOSED TO: 35 `aivec` rows and 3 `aistr` rows. **List 10's ship vectors** - idx0 (80,1970)<-[5264], idx1 (384,1986)<-[6976], idx2 (384,2002)<-[6992], idx3 (816,7072)<-[11 ship ids]. **List 8's routes** - (2002)->[256], (1970)->[384], (1538)->[240]. Plus list 1's names as strings ("Egg Thief Mk 4", "Egg Thief Mk 5", "Bravestar Mk 3"), list 3's and list 12's vectors (12 elements resolving 3/15/1/5/4/6/20/22/11/7/1/7 ship ids). Under BP's noise mask the deep run's shallow words are ELEMENT-FOR-ELEMENT IDENTICAL to BP's run B, so `deep=on` is additive and does not disturb the block. **TWO CROSS-CHECKS NOW POSSIBLE FOR THE FIRST TIME, BOTH PASS: (1) the block's ship<->fleet pairing matches the save it produced** - list 10 gives fleet 1970 <- ship 5264 at system 80, and `bp-pinB-turn28.sav` is exactly the save where Flt[1970] holds Ship[5264]; the resolution's "the visit order is written into the block" is now verified END TO END, block -> save. **(2) The list-8 move goes to the group at system 80 in BOTH orders** (fleet 1970 with route [384] here; fleet 1986 with the same route in run A - both are the system-80 group), which confirms the resolution's section 3 qualification from the command stream instead of by inference. OUTCOME SET AFTER FIVE PROCESSES ON THIS STATE: `e913ff41...` x3 (BP's L unpinned, BP's A pinned, BR's probe pinned+airng, all 384-first), `724528ff...` x2 (BP's B, BR's deep, both 80-first). **NO THIRD FILE IN FIVE PROCESSES, ACROSS THREE INSTRUMENT CONFIGURATIONS**, with both members reproduced at least twice - the residue is a small enumerable order, which is what C-set's shape needs. Not a proof that k=2. Artefacts: `verify/results/shim/br/BR2-deep-aiorders.txt`, `BR2-shim.log`, `shim.cfg.brdeep`; the save is byte-identical to `verify/results/saves/bp-pinB-turn28.sav` and is deliberately not duplicated |
```
Edits to existing rows:
- **Row 62** — VM146: **lane BR held it 2026-09-09 02:21–02:47 local for the visit-order probe and
the Rung-B deep record, and released it restored** and hash-verified: `SavedGames` back to the
9-file pre-BR set with both autosaves byte-identical to `C:\SOTS\ui\preBP\` (`a3f9dc4b…`,
`d59bb9f2…`), `shim.cfg` `hooks=off`, `binkw32.dll` `07c96294…`, `shim.trace.jsonl` removed, game
process **not running, exactly as found**. `ad-turn27-two-raiders.sav` still on disk, so BP's
Load-dialog geometry **still holds and was re-verified from a screenshot**: 7 rows from y=260 at
29 px pitch, row 1 at (400,260). Left `C:\SOTS\shimdist-bp\shim.cfg.{brprobe,brdeep}` and
`C:\SOTS\ui\br-probe-turn28{,-pre}.sav`, `br-deep-turn28.sav`, `br1-*`, `br2-*`;
`click_helper.ps1` and BP's three helpers untouched. **BETTER INSTRUMENT THAN THE WALL, AND IT
RETIRES BP'S FOUR-WASTED-CLICKS GOTCHA: take the screendump yourself** —
`echo 'screendump /tmp/x.png -f png' | qm monitor 146` on spicy, then `scp` — that is the **live**
framebuffer with no poll cycle in it. Twelve screenshots, zero ambiguous frames, zero wasted
clicks; BP's "wait 12–16 s" is only needed for the wall's `/shot/<id>.png`. Note
`tools/vmshot.py` cannot be used from the WSL host: it imports PIL and PIL is not installed.
**GOTCHA: `bpshot.ps1` sleeps 3 s then prints `ui\log.txt`, but the click-helper task writes that
file at the END of its batch** — for any batch longer than ~3 s you get the *previous* batch's log
(mine printed a 37-minute-stale timestamp on the first call). Read the log in a separate call or
ignore it and screenshot. **TIMINGS, TWO RUNS: main menu ~2 min 45 s** (`fg` + `key {ESC}` ×3
spaced 2.5 s, screenshot-verified, never slept-and-clicked); the click path ~2 min at one click
per helper call; **turn-27 load 3 min 20 s then 1 min 55 s**; **End Turn ~4 s** with this hook set
— BP's "~35 s" is generous and the autosave mtime is the reliable completion signal.
- **Row 326** (the per-process AI client seed) — append: `MECHANISM MEASURED LIVE 2026-09-09 (lane BR, VM146): the per-process global generator at 0x00af6e58 is drawn EXACTLY THREE TIMES IN THE WHOLE PROCESS, three words, from ONE return address va=0x00784f9e - inside StrategyNetworkClient::OnMessage 0x00784640 and 16 bytes before the RunAI call site lane AI1 recorded at OnMessage+0x96e - once per AI client, at the same log timestamps as the three aiseed calls. That is this row's mechanism, with a consumer address and a call count instead of an inference. It is also the ONLY draw that generator takes: its count is 3 at every airng bracket from the first AI client to the end of the turn.`
- **Row 360** — append to the resolver's queued note: `AND THE RESIDUE IS NOT A DRAW: lane BR (2026-09-09, VM146) measured zero foreign words and zero foreign calls in all three AI clients' OnResumePlaying brackets, residual=0 (so not an inlined draw either), and the global generator motionless through the turn. RNG is excluded by measurement; an address-keyed container is the only hypothesis left.`
- **Row 415** — append: `Lane BR reproduced the 384-first branch a third time (e913ff41..., byte-identical to BP's A and L) and the 80-first branch a second time (724528ff..., byte-identical to BP's B). Five processes, two files, no third.`
- **Row 333 / the Rung C row** — append: `PRECONDITION MET 2026-09-09 (lane BR): the per-client draw ledger is taken and it is clean - zero foreign draws in every AI bracket on ad-turn27, so the residual visit order is not an RNG input and (save, seeds, visit order) is the complete input tuple as far as any generator is concerned.`
- **The Rung B row / backlog section 2 Rung B** — append: `DONE 2026-09-09 (lane BR run 2): the first replayable rich-turn record exists. It is on the 80-first branch (724528ff..., byte-identical to bp-pinB-turn28.sav), not the e913ff41 branch section 6 named, and that is immaterial because list 10 records the visit order. The deep block follows list 10's ship vectors and list 8's routes, and its ship<->fleet pairing matches the save it produced - "the visit order is written into the block" is now verified end to end.`
- **`method-rules.md` rule 26 (d)** — no change proposed to the wording; note in passing that lane BR
is its second application and its first *successful* one: the pinned+instrumented run reproduced
lane BP's natural run L byte for byte, which is what licenses reading the ledger.
Docs to correct in place (rule 11), proposed, not done by this lane:
- `findings/subsystems/roll-parity.md` — `airng`'s behavioural neutrality can be upgraded from "two
fresh processes on the published oracle" to "and it reproduced a natural unpinned run of
`ad-turn27` byte for byte on a rich AI turn (lane BR)".
- `guides/lab-screen-wall.md` — add the direct-screendump one-liner as the recommended path for a
lane that is *driving* a guest (the wall is for watching), and record that `tools/vmshot.py`
needs PIL, which the WSL host does not have.
- Any doc that still says the `0x0069dbb0` fuse "has never been observed firing" — it fired on the
**load** path in this run, on each client's own generator, three sites' worth of words inside
`life_in`. Its *turn-time* behaviour is still untested and that distinction should be written down.