BR: predictions committed before the run - P1-P4 of the fleet-visit-order resolution, on VM146
This commit is contained in:
parent
8552720ea8
commit
a05f54d2b0
1 changed files with 114 additions and 0 deletions
114
findings/control-flow/ai-visit-order-probe.md
Normal file
114
findings/control-flow/ai-visit-order-probe.md
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
# 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
|
||||
|
||||
*(filled in with the run)*
|
||||
|
||||
---
|
||||
|
||||
## 3. The result
|
||||
|
||||
*(filled in with the run)*
|
||||
|
||||
---
|
||||
|
||||
## 4. Verdict
|
||||
|
||||
*(filled in with the run)*
|
||||
Loading…
Add table
Reference in a new issue