610 lines
49 KiB
Markdown
610 lines
49 KiB
Markdown
# 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.
|