BQ: probe 1 predictions, committed before either run

Lane BQ (VM145) takes the seed-exposure predicate's first forward test.
Part 1b: ar-oracle-A-pre.sav + one End Turn from a LOAD must reproduce
7a8b3d5e... (it has only ever been reached by continuation). Part 1:
ar-oracle-A-post.sav in two fresh hooks=off processes must DIFFER, confined
to Player[32]'s research leaves, because that save carries ResTNm == '' for
the one player that can research.

Also records the exposure facts (ResTNm / NumDes / NumOwn / completions) for
every player on both inputs, and names a false-positive class in the predicate
before the run: four NPC players carry ResTNm == '' on the very turn whose
control agreed, and all four have NumOwn == 0.
This commit is contained in:
alex 2026-09-09 01:04:12 -04:00
parent 947f205867
commit be1426630c

View file

@ -0,0 +1,223 @@
# The seed-exposure predicate's first forward test — probe 1 (parts 1b and 1)
- **Type:** control-flow / determinism (two `hooks=off` measurements from saves already on disk; no
build, no shim config change, no instrument)
- **Owner / date:** lane **BQ** · 2026-09-09 · guest **VM145** (`sots-re-win10-145`, 192.168.10.145)
- **Spec:** `findings/resolutions/2026-09-09-seed-exposure-is-a-predicate.md` §6, probe 1
- **Tests:** `guides/method-rules.md` rule 26 corollary (c) — the predicate written from lane AR's
falsified P7, so far supported only by three states read *after* the fact
- **Depends on:** `findings/control-flow/raid-target-pick-verdict.md` §6 (lane AR's pair)
---
## 1. Predictions, committed before either run (rule 2)
*Everything in §1 and §2 was written and committed before the game was launched on VM145 and before
any hash was read. It is not edited after the fact, only annotated with verdicts in §5.*
### 1.1 What is actually at stake
The resolver ruled that the per-process AI client seed (row 326) is present in **every** process on
**every** turn, and reaches the save **only** through a decision whose outcome set is larger than one
given the state — and that whether such a decision is reached is a **predicate on the pre-turn save**.
That ruling currently rests on three states read *after* their controls were run (lane AD's turn 28,
lane AS's turn 16, lane AR's turns 38–39). It has never made a forward prediction.
This lane makes two, on states nobody has run, and both can fail.
### 1.2 Part 1b — the precondition
**Procedure.** `ar-oracle-A-pre.sav` (Frame 38, sha256 `15b99255e1f03dab3e35ab8c1ac64f221cb5aa9321f113c7a6e3d1263c3f34ca`),
one fresh process, `hooks=off`, **one End Turn**, no other input.
> **P1b — committed.** The resulting `(Autosave).sav` (Frame 39) hashes to
> `7a8b3d5eb3a60ebac9f40646d3e4b15768a24a0af047a439ce090c7cf38e8b38`.
Why it matters. Lane AR's `15b99255…` → `7a8b3d5e…` step has only ever been reached **by
continuation** — the second of two End Turns inside one process that started from
`ar-turn37-816raiders.sav`. A calibration pair for the standalone must be a **load → turn**
procedure. If P1b holds, the single-turn pair is certified in that form and is the first pair
anywhere that exercises the trade-raid roll (four raid rolls, one word each, no encounter). If it
fails, the pair remains valid **only** as the two-turn procedure from turn 37, and the resolution
names the first suspect: the **resave canonicalisation** (`determinism-oracle.md`, round-trip
section).
> **P1b-aux — committed, and it costs nothing.** The same run also writes
> `(Autosave EndTurn).sav`, which is the state **as End Turn is pressed** — i.e. a resave of the
> file that was loaded. I predict it hashes to `15b99255…`, the input's own hash. **This is a direct
> test of the resave-canonicalisation suspect**, taken in the same run whichever way P1b goes:
>
> - P1b holds **and** P1b-aux holds ⇒ load→resave is byte-exact here and the pair is clean.
> - P1b fails **and** P1b-aux fails ⇒ the divergence is present *before the turn runs*; it is the
> round trip, not the turn, and the resave canonicalisation is confirmed as the cause.
> - P1b fails **and** P1b-aux holds ⇒ the round trip is exact and the **turn** diverged from its
> continuation form. That is the interesting failure and it is not one the resolution anticipated;
> it would mean a load boundary changes turn 39's outcome, and it is a resolver case, not a lane
> result.
> - P1b holds **and** P1b-aux fails ⇒ the resave is not byte-exact but is behaviourally equivalent;
> the pair is certified and `determinism-oracle.md`'s round-trip section needs a note.
### 1.3 Part 1 — the exposure test
**Procedure.** `ar-oracle-A-post.sav` (Frame 39, sha256 `7a8b3d5e…`), **two fresh processes**,
`hooks=off`, **one End Turn each**, any encounter query resolved with **`Auto Resolve Peacefully` in
both**.
> **P1 — committed.** The two `(Autosave).sav` files **differ**, and the difference is confined to
> `Player[32]`'s `TechTree/*`, `ResTNm`, `otch`, `Events`, `turnstats/…/tch` and `Summary/Checksum`,
> while `/Sim/RNG`, `/Sim/trdmgr`, **every** `Player[16]` leaf and **every** player-0 fleet are
> identical.
The reasoning, and it is the predicate speaking: `ar-oracle-A-post.sav` carries `ResTNm == ''` for
Player[32] (§2). By the AS precedent (`as-turn15 → 16`, 22 leaves, entered with `ResTNm == ''`) and
the row-326 precedent on `turn1-state`, that is a research-pick turn. So the predicate says, **in
advance**, that lane AR's pair must not be extended by a turn — and this run is what makes that a
measurement rather than an inference.
**How P1 can be wrong, and the symptom of each way** (rule 2):
| way it could be wrong | symptom |
|---|---|
| a producer supplied the target, so the pick had an outcome set of size 1 (as for player 32 on `turn1-state`) | the two files **agree** byte-for-byte; the predicate survives but needs a **producer gate**, and lane L4's `airesearch=on` dump names which producer returned non-null |
| something else on turn 40 is exposed as well as the pick | the files differ, but **outside** the named leaf set — e.g. in fleets, `trdmgr`, or `Player[16]` |
| the pick is exposed but its outcome-set is 1 for a different reason (only one affordable node) | files agree; same follow-up as the producer case, and `otch`/`TechTree` at turn 40 says which node was taken |
| VM145 is not byte-faithful to the lineage | **P1b fails** as well, and part 1b is the guard against reading part 1 off a guest that cannot reproduce anything |
**A negative here is a result, not a null.** If the two files agree, the honest statement is *"no
exposed decision was reached on turn 40 either, and the pick is therefore producer-supplied on this
state"* — never *"the AI is deterministic here"* (rule 26 (c)).
### 1.4 A false-positive class in the predicate, named before the run
Read off the two saves (§2), and stated here because it is a *pre-run* correction to the predicate
as the resolution words it:
**`ResTNm == '' at turn start` is true of four players on `ar-oracle-A-pre.sav` — the turn whose
control agreed byte-for-byte.** Players 528 (`Alien Menace`), 544 (`Peacekeeper Enforcer`), 560
(`Von Neumann`) and 576 (`Independent Colony`) all carry `ResTNm == ''` on turn 38 **and** turn 39,
and player 16 (the human) does too. They have `NumOwn == 0`: no colonies, no research income, no
pick to make. So the raw predicate has a known false-positive class already sitting inside the very
state that falsified AR's P7.
The sharp form the next lane should use is therefore:
> `ResTNm == ''` **at turn start, for a non-eliminated AI player with `NumOwn > 0`**, names a
> research-pick turn.
On `ar-oracle-A-post.sav` exactly one player satisfies that: **Player[32]**, `NumOwn 18`. That is
the whole basis of P1, and it is why P1 names Player[32]'s leaves and no one else's.
*(Note for honesty: players 496 and 512 — the two `Spengler` NPCs — hold non-empty `ResTNm` and also
have `NumOwn == 0`. They are not evidence either way; they are listed in §2 for completeness.)*
### 1.5 What this lane will not settle (rule 15)
- **Two processes, not three**, for part 1 — rule 26's bar, matching AR's.
- **One state.** Neither part says anything about `ad-turn27`, which is probe 2's job on VM146.
- **The producer gate is not run here** unless part 1 comes out as agreement and time allows; if it
does not, this document names it as the next step rather than guessing at it.
- **`0x0069dbb0`'s 3–40-turn fuse cannot fire** in a one-turn-from-load run, by construction — so
neither part can say anything about it, in either direction.
- **No instrument.** `hooks=off` throughout, so this lane measures behaviour and never attributes it
to a draw site. The consumer identification is probe 3's job.
---
## 2. The exposure facts, read off the saves before the runs (rule 26 (c))
`uv run python3 verify/save-reader/save_reader.py --json`, three saves on the AD/AR lineage.
`NumDes` = the `designs` list length, `NumOwn` = the `owners` list length (both are the on-wire count
prefixes; verified against the `--dump` tree at `NumOwn`/`NumDes`). "ships +" is the per-owner
`ShipID` set delta from the previous save in the lineage.
### 2.1 `ar-oracle-A-pre.sav` — Frame 38, `ModCount 2108`, the input to part 1b
| PID | PlyrIdx | name | species | NPC | `ResTNm` | `NumDes` | `NumOwn` | ships | fleets |
|---|---|---|---|---|---|---|---|---|---|
| 16 | 0 | `re` (human) | 0 | no | `''` | 6 | 3 | 5 | 5 |
| **32** | **1** | **The Eternal Empire** | 2 | no | **`BIO_EnvTail`** | **47** | **18** | 243 | 59 |
| 496 | 2 | Spengler | 0 | yes | `DRV_PlsFiss` | 0 | 0 | 0 | 0 |
| 512 | 3 | Spengler | 2 | yes | `XNC_TrnsMorr2` | 0 | 0 | 0 | 0 |
| 528 | 4 | Alien Menace | 4 | yes | `''` | 19 | 0 | 0 | 0 |
| 544 | 5 | Peacekeeper Enforcer | 4 | yes | `''` | 1 | 0 | 0 | 0 |
| 560 | 6 | Von Neumann | 4 | yes | `''` | 6 | 0 | 0 | 0 |
| 576 | 7 | Independent Colony | 4 | yes | `''` | 1 | 0 | 0 | 0 |
**Predicate reading for turn 38→39:** the only player that can research holds a target
(`BIO_EnvTail`), `NumDes` is constant at 47, `NumOwn` constant at 18. **No exposed decision
predicted** — which is exactly what AR measured (three processes agreed). Part 1b is therefore a
*re-run of an agreeing turn from a load*, and its only open question is the load boundary itself.
### 2.2 `ar-oracle-A-post.sav` — Frame 39, `ModCount 2147`, the input to part 1
| PID | PlyrIdx | name | species | NPC | `ResTNm` | `NumDes` | `NumOwn` | ships | fleets |
|---|---|---|---|---|---|---|---|---|---|
| 16 | 0 | `re` (human) | 0 | no | `''` | 6 | 3 | 5 | 5 |
| **32** | **1** | **The Eternal Empire** | 2 | no | **`''`** ← **pick signature** | **47** | **18** | 245 | 59 |
| 496 | 2 | Spengler | 0 | yes | `DRV_PlsFiss` | 0 | 0 | 0 | 0 |
| 512 | 3 | Spengler | 2 | yes | `XNC_TrnsMorr2` | 0 | 0 | 0 | 0 |
| 528 | 4 | Alien Menace | 4 | yes | `''` | 19 | 0 | 0 | 0 |
| 544 | 5 | Peacekeeper Enforcer | 4 | yes | `''` | 1 | 0 | 0 | 0 |
| 560 | 6 | Von Neumann | 4 | yes | `''` | 6 | 0 | 0 | 0 |
| 576 | 7 | Independent Colony | 4 | yes | `''` | 1 | 0 | 0 | 0 |
**Predicate reading for turn 39→40: EXPOSED.** Player[32] enters with `ResTNm == ''` and `NumOwn 18`.
`otch` moved 46 → 47 across turn 39 (`BIO_EnvTail` completed), which is the same shape AS recorded.
### 2.3 Ship completions on the lineage, for the fleet-assignment half of the predicate
| transition | `ModCount` | PID 16 ships | PID 32 ships | reading |
|---|---|---|---|---|
| turn 37 → 38 | 2057 → 2108 | **−7408** (`Zeta Fleet`'s destroyer, lost in the encounter) | **+8784, +8800** | 2 completions, into existing fleets — not a batch |
| turn 38 → 39 | 2108 → 2147 | none | **+8816, +8832** | 2 completions, into existing fleets — not a batch |
Two ships a turn into existing `Freighters` fleets is the *quiet* fleet consumer, not the
thirteen-into-five-new-fleets batch that AD's turn 28 carried. `designIds` is constant at 95 and
`fleetIds` at 64 across both transitions, corroborating "no design turn, no fleet creation".
**So: on the input to part 1b the predicate says NOT exposed; on the input to part 1 it says
EXPOSED, via the research pick, for exactly one player.**
---
## 3. Procedure and configuration
`hooks=off` throughout, no build (rule 24 is satisfied trivially — nothing is compiled).
| item | value |
|---|---|
| guest | VM145 `sots-re-win10-145`, 192.168.10.145 |
| shim build | `C:\SOTS\shimdist-l4\binkw32.dll`, `BUILD_ID l4r-20260908T2208Z` |
| config | `C:\SOTS\shimdist-l4\shim.cfg.l4off`, **unmodified** — `hooks=off`, installs nothing |
| why this build | lane L4 proved *on this guest, with this exact DLL and this exact config* that VM145 reproduces the campaign's published autosave oracle byte-identically (`ai-order-capture.md` §3: `bb4fd9ac89f41e3b` / `978041acd168b56e`). It is the only hooks=off pair on VM145 with a published byte-fidelity result behind it |
| `SavedGames` | reset to **exactly one file** — the run's input save — before every launch, so the Load dialog has one row and its position is re-derived from a screenshot anyway |
| main menu | verified from a `qm monitor` screendump (`tools/vmshot.py --one 145`), never by sleeping |
| encounter query | detected by sampling the `Done` pixel at (233, 673): ≈(183,18,0) query up, ≈(8,8,8) map. `Auto Resolve Peacefully` (667,641), `Done` (233,673) |
**VM145 as found**, recorded so it can be put back (§8):
```
binkw32.dll 15,527,327 B sha256 903527f4a698eea9fbe25f3a6236657c7d8348f994eef394696f187e5e554b97
(= shimdist-recap, BUILD_ID recap-7584bad-20260908T0615Z)
shim.cfg sha256 0ae410cc72fe155837d711c78543e14b1f5743310cd023298eb1e5bbd5457e71 (hooks=trace, lane R recapture)
SavedGames 9 files, saved to C:\SOTS\ui\preBQ\
game not running
```
---
## 4. Results
*(added after the runs; nothing above this line is edited)*
---
## 5. Verdicts on the committed predictions
*(added after the runs)*
---
## Proposed board rows
*(added after the runs)*