P1 falsified. Two processes with identical pinned AI client seeds produced different turn-28 autosaves from ad-turn27-two-raiders.sav, so a per-process input other than the seed reaches a rich turn and C-exact is false on this state. Resolution trigger, handed back rather than chased. But the pin did almost all the work. AD's unpinned pair differed in 94 leaves across designs, ship records, money, both build queues, ModCount, NumFlts, DesignIDs[] and FleetIDs[]. This pinned pair differs in 35 of 61147, and all 35 are one transposition: fleets 1970 and 1986 exchange their entire contents. Every decision leaf is identical. The command block says the same from the input side. Runs L (unpinned) and A (pinned to L's observed seeds) wrote BYTE-IDENTICAL autosaves, which gives a noise mask no previous lane could build for this state; against it, A and B differ in exactly three words - one fleet-move fleetId and two systemIds - and list 10's fleet ids are in the same order in both. The id counter is deterministic; what varies is which newly formed ship group each id lands on. Also measured: the save has seven non-human players and the engine builds THREE AI clients (RunAI fires 3x, ids 32/496/512); the four NPC factions get no client and no seed.
35 KiB
The pinned-seed probe on a rich AI turn — is the client seed the only per-process input?
- Owner / date: lane BP · 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), VM141 (lane AZ) and VM144 (lane AP) untouched.
- Trigger:
findings/resolutions/2026-09-09-seed-exposure-is-a-predicate.md§6, probe 2 — the first of the three probes, because it can invalidate C-exact. - Build:
bp-989c692-20260909T0505Z, built in/srv/re-lab/build/sots-engine-bpafterssh spicy 'rm -rf …'of the whole tree (rule 24), from a lane-privategit worktreeat~/sots-engine-bp(branchwip/bp) with no localbuild*shipped (rule 21). Deployed toC:\SOTS\shimdist-bp. - Input:
verify/results/saves/ad-turn27-two-raiders.sav, sha2561c8baa27680809d585ab1728391e82729642d32aaedffd5bf95b616f0a11a436(lane AD's published value; re-verified on this guest before the first run — §3.1).
0. The question, in one paragraph
The campaign holds that the original's AI is a deterministic function of (save, per-client
seed) — "C-exact" — and that its apparent non-determinism is one 32-bit word drawn per AI client
at construction from a per-process global (resolution 2026-09-08, board row 326). Row 360 proved
that pinning those seeds collapses three processes to one autosave. It proved it on
turn1-state, an early-game turn, and nowhere else. ad-turn27-two-raiders.sav is the richest
AI turn this campaign owns — thirteen ships complete into five new fleets, a design is created, a
system is colonised — and two hooks=off processes on it differ in 94 leaves
(raid-gate-multiplicity.md §5). The resolver established that that variation is not the
design content (the two Bravestar Mk 3 bodies are byte-identical apart from DesID) and not
a research pick (ResTNm held for Player[32]); it is the build / fleet-assignment / colony layer
and the id allocation downstream of it, and its consumer is unidentified. So reading 3 — a
non-seed per-process input — is not excluded on rich states. This probe decides it.
1. The prediction, committed before the run
P1 (the headline). Two fresh processes loading
ad-turn27-two-raiders.savwith the AI client seeds pinned by the constructor-argument overwrite, one End Turn each, write byte-identical(Autosave).savfiles, andstate_checksum.py --floats bits --mask noneprints IDENTICAL over roughly 67,000 leaves.P2. The
(Autosave EndTurn).sav(pre-turn snapshot, written before the AI runs) is byte-identical between the two processes as well. This is the weaker half and it is expected to hold whatever P1 does: lane AD saw the pre-turn autosave agree bit-for-bit across three processes and two configurations, so the load path is already known to be deterministic.P3. The pinned pair also reproduces run L — the unpinned
aiseed=logrun whose observed seeds the pin uses (§2.3). This is CB's C3/C5a/C5b shape applied to a rich turn: three processes, three sets of natural seeds, one autosave. Weaker than P1 (it can fail for a reason that leaves P1 intact — see the falsifiers) and worth much more if it holds, because it says the pinned run reproduces a turn that actually happened rather than a synthetic one.P4 (the exposure predicate, tested in passing).
ad-turn27is exposed on all three of the resolution's counts for Player[32] — a design is created, thirteen ships complete, a system is colonised. If P1 holds, then an exposed turn is reproducible once the seed is pinned, which is the whole content of C-exact on the turns that matter.P5. The AI command blocks dumped by
aiordersare identical between the two processes, element for element, on every list of every block. If P1 fails, P5 is the localiser: blocks identical + autosaves different puts the non-seed input downstream of the AI's decision; blocks different puts it inside it.
1.1 How this could be wrong, and the symptom of each way
| way | symptom |
|---|---|
| Reading 3 is alive — some per-process input other than the seed feeds this turn | P1 fails. The leaf diff localises it. This is a resolution trigger, not a lane result: the resolution says so in as many words, so this lane localises by sub-tree, names the leaves, and stops. |
| The pin is half-applied — a client with a net id not in the list passes through unpinned | The two processes differ, for a reason that has nothing to do with reading 3. Defended by construction: the wildcard *=<hex> is set as well as every observed id, so no client can pass through, and shim.log prints aiseed call=… observed=… used=… pinned=1 for every single call. Every call must read pinned=1. A run with even one pinned=0 is void. |
The pin is not applied at all — aiseed=pin with no values |
shim.log prints aiseed: PIN MODE WITH NO PINS -- every seed passes through unchanged, so this run is NOT pinned and must not be reported as one. Checked before either autosave is read. |
| The wrong mechanism was used | airng.pin_seed re-seeds the generator at bracket entry and is a declared perturbation; it would test a different thing. This lane does not set it. airng=off is explicit in both configs. |
| The instrument perturbs the turn (rule 19) | Not separable here, and stated rather than hidden: a pin cannot be applied by a process with no hooks, because hooks=off returns from Shim_Init before the aiseed module is installed. §2.2 lists exactly what is installed. Both processes carry the identical instrument, so the A/B comparison is internally valid; what it cannot do is speak about the un-instrumented game. |
| A stale binary (rule 24) | The build tree was rm -rf'd on CT111 before the rsync; BUILD_ID is checked in shim.log on every run and quoted in §3. |
| The click path lands somewhere else | Every dialog step is screenshotted and verified; no sleep-and-click. Row positions are re-derived from a screenshot of the Load dialog, not carried over from another lane. |
1.2 What this probe cannot decide, whatever it says
It is a statement about one save, one procedure, one build. Rule 26 corollary (c): a control
that agrees certifies a procedure, not a state. If P1 holds it says "on this turn, with these
seven clients pinned, nothing else per-process reached the save" — it does not say the AI is
deterministic, and it does not transfer to a turn that reaches a consumer this one does not. In
particular the 3–40-turn fuse at 0x0069dbb0 cannot fire inside one turn of a load and is
therefore untested by this probe, exactly as it was untested by AR's two-turn pair.
2. The procedure
2.1 Why the constructor-argument overwrite and not airng.pin_seed
aiseed=pin detours Game::StrategyApp::RunAI and replaces its fourth stack argument — the
word the StrategyClient constructor is about to hand to RNG_Seed — before the callee reads it.
The client's generator is therefore constructed from the pinned word and its whole stream, from
the first draw, is the stream that word implies. airng.pin_seed (lane PAR) re-seeds an already
constructed generator at bracket entry; it discards whatever the client drew before that point and
is a declared perturbation. The resolution names the first and forbids the second. Getting this
wrong would invalidate the probe, so it is stated here rather than left to the config.
2.2 The hook set, stated in full — and a defect in the mechanism this lane inherited
aiseed lives in the ai_orders module, and install_ai_orders() is only reached when
hooks != off. So there is no such thing as a hooks=off pinned run. The minimum instrument
that can carry a pin, and the one both processes carry, is:
- the
Mars::Application::Initializedetour (the shim's own entry point); - the seven draw-site detours — installed unconditionally whenever
hooks != off; - one
aiordersdetour onStrategySim::ApplyTurnCommandBatch(aiprobes=off, so none of the entry probes; lane H's non-neutral probe index 8 is not installed); - one
aiseeddetour onStrategyApp::RunAI.
Every template hook is off by name. That matters more than it looks:
trace::Config::mode_for falls through to default_mode for any hook not named, and
default_mode under hooks=trace is trace — so a hook omitted from the list is silently left
installed.
Inherited defect, reported not worked around.
src/shim/shim.cfg.cbpin— the file the resolution points at — names 20 template hooks and omits six that existed when it was written:Game::StrategyServer::BeginProcessTurn, the threeGame::SVSOSwarmQueen::*hooks,Game::SVSOSlaversRefuel::UpdateDifficultyTierandMars::RNG::Seed. Underhooks=tracethose six default to trace mode, so lane CB's pinned runs C5a/C5b carried a larger instrument than their config comment implies. It does not damage CB's result — both processes carried the same six, and CB's conclusion rests on an A/B agreement — but the next lane to copy that file inherits them.shim.cfg.bppinnames all 28 registered hooks.Second, smaller defect in the same file. Its header comment wraps onto a line that is not commented: line 4 of
shim.cfg.cbpinreadsaiseed.values=32=e70a4703,496=0c63ca36,512=372be4df\.` — a live config line ending in a stray backtick and a full stop, four lines above the real one. Harmless if the parser is last-wins, and nobody has checked which it is. Reported so it can be fixed rather than rediscovered.
2.3 Three runs, not two
The resolution costs the probe at two loads. This lane takes three, and the extra one is run L:
| run | config | seeds | End Turns | purpose |
|---|---|---|---|---|
| L | shim.cfg.bplog |
aiseed=log — observed, not changed |
1 | enumerate the net ids and their natural seeds; produce a natural reference autosave |
| A | shim.cfg.bppin |
pinned to L's observed values, every id plus the wildcard | 1 | the probe |
| B | shim.cfg.bppin |
identical | 1 | the probe, second fresh process |
Why the third run is worth its nine minutes:
- Nobody has ever listed this save's AI net ids. The save has seven non-human players (§2.4)
but the number of players is not the number of
StrategyClients. The alternative the resolution allows — the bare wildcard — pins every client to the same word, which is a valid intervention but not a natural one. - It makes the pin reproduce a turn that happened. Lane CB's rule: pin to values an unpinned run of the same save observed for itself. P3 is then a real prediction rather than a definition.
- Two runs agreeing on a
k > 1workload is a1/kcoincidence; three is1/k². That is exactly the argument CB used to justify its own third run, and it applies here with more force because nobody knowskon a build turn.
shim.cfg.bplog and shim.cfg.bppin are byte-identical except the aiseed= line and the
values, so run L is comparable with A and B.
2.4 The exposure facts, read off the input save before any run
Rule 26 corollary (c) says to write the exposure facts next to the hashes. Read from
ad-turn27-two-raiders.sav with verify/save-reader/save_reader.py --dump --json:
| PlyrIdx | PlayerID | name | ResTNm at turn start |
NumOwn |
NumDes |
|---|---|---|---|---|---|
| 0 | 16 | re (human) |
'' |
3 | 6 |
| 1 | 32 | The Eternal Empire (Tarka) | BIO_TerBac (held) |
15 | 46 |
| 2 | 496 | Spengler (RebelAI) | DRV_PlsFiss |
0 | 0 |
| 3 | 512 | Spengler (RebelAI) | XNC_TrnsMorr2 |
0 | 0 |
| 4 | 528 | Alien Menace | '' |
0 | 19 |
| 5 | 544 | Peacekeeper Enforcer | '' |
0 | 1 |
| 6 | 560 | Von Neumann | '' |
0 | 6 |
| 7 | 576 | Independent Colony | '' |
0 | 1 |
Ships completing this turn: 13, into five new fleets (ShipIDs +13 −1), with NumDes 46→47
(Bravestar Mk 3) and NumOwn 15→16 — measured by the resolver from the 27→28 transition, quoted
here as the prior it is, and re-derivable from this lane's own output saves.
One thing this table says that the resolution's §3 does not. The resolution reports "AD's
variation was not a research pick — Player[32] entered turn 28 with ResTNm = 'BIO_TerBac'", which
is correct. But four other AI players enter this turn with ResTNm == '' (528/544/560/576) and
none of them contributed a leaf to AD's 94 — every one of the 94 is Player[32]'s or the global
id counters'. All four have NumOwn == 0. So the predicate as written in rule 26 corollary (c) —
"ResTNm == '' names a pick turn" — is necessary and not sufficient: a player with no colonies
has no research income and does not reach the pick, whatever its ResTNm says. That is a
measurement on the input save, independent of how the runs come out, and it is offered as a
refinement of the predicate rather than a correction of the resolution's Player[32] claim, which
stands.
3. The result
3.0 Lead
P1 is falsified. Two processes with identical pinned seeds produced different turn-28 autosaves. So a per-process input other than the AI client seed reaches a rich turn, and C-exact — "nothing else per-process reaches the turn" — is false on this state.
And the falsification is far more informative than a bare failure, because the pin worked.
Lane AD's un-pinned pair differed in 94 leaves spread over Player[32]'s designs, ship records,
savings, maintenance, build queues, /Sim/ModCount, /Sim/NumFlts, /Sim/DesignIDs[],
/Sim/FleetIDs[] and four turnstats rows. This lane's pinned pair differs in 35 leaves of
61,147, and every single one of them is one transposition: fleet ids 1970 and 1986
have their entire contents exchanged. Nothing else in the save moves. In the AI's own emitted
command block — 9 blocks, 81 elements — the two runs differ in exactly three words, and all
three are the same transposition.
So the seed accounted for every decision; what is left is an ordering.
3.1 What was run
Three fresh processes on VM146, same guest, same dist (C:\SOTS\shimdist-bp, BUILD_ID bp-989c692-20260909T0505Z), same input save, same click path, each verified from a screenshot at
the main menu, at the Load dialog, at the selected row, at the lobby and on the turn-27 map.
| run | config | seeds observed (natural) | seeds used | End Turns |
|---|---|---|---|---|
| L | shim.cfg.bplog, aiseed=log |
156ebbbd / fe7b2826 / 0ed341d1 |
its own | 1 |
| A | shim.cfg.bppin, aiseed=pin |
4a2db187 / 72874c54 / 4ac40447 |
L's | 1 |
| B | shim.cfg.bppin, aiseed=pin |
b5f6e243 / dd8eb177 / ce156a3b |
L's | 1 |
Net ids 32 / 496 / 512 in that order in all three processes. Nine distinct natural seeds, no value shared between any two processes — lane L1's per-process seeding reproduced a fourth time, now on a turn-27 state.
Instrument armed and verified from shim.log, not assumed (rule 1), identically in all three:
build bp-989c692-20260909T0505Zin every run;- 27 template hooks
mode=off (not installed), plusselftest: … mode=off— every registered hook off, none defaulted on; - seven
drawsite:detourscreate=MH_OK enable=MH_OK;aiorders: … probes=0 of 20; one batch hook and oneaiseedhook, bothMH_OK;aicfg … detours=2; - zero
ignoring unknown keylines and zeroCOVERAGE:lines in any run; diffof the 42config:lines of A's and B'sshim.log: identical;- runs A and B:
aiseed pinfor net ids 32/496/512 and the wildcard, thenaiseed call=1/2/3 … pinned=1— three of three pinned in both, nopinned=0, the wildcard never used (no fourth client), and noPIN MODE WITH NO PINSline.
Run L corrects the brief. The save has seven non-human players; the engine constructs three
AI clients. RunAI fires exactly three times. The four NPC factions — 528 Alien Menace, 544
Peacekeeper Enforcer, 560 Von Neumann, 576 Independent Colony — get no client, no RunAI call and
no seed. This is why run L was worth its nine minutes: the wildcard would have pinned three clients
and a seven-id list would have been three pins and four dead entries, and neither would have said
so.
3.2 The hashes, with the exposure facts on the same lines (rule 26 (c))
Input: ad-turn27-two-raiders.sav, 1c8baa27680809d585ab1728391e82729642d32aaedffd5bf95b616f0a11a436,
100,809 B — re-verified on the guest after transfer, equal to lane AD's published value.
Exposure, from §2.4 and confirmed by the transition: Player[32] "The Eternal Empire" enters with
ResTNm = BIO_TerBac held (no pick), NumDes 46, NumOwn 15, and 13 ships completing;
players 496 and 512 hold targets with NumOwn = 0 / NumDes = 0; the four NPC factions have
ResTNm == '' and NumOwn == 0 and get no AI client at all. The turn is exposed on the design,
fleet-assignment and colony counts and not on the research pick.
(Autosave EndTurn).sav (pre-turn) |
(Autosave).sav (post-turn) |
|
|---|---|---|
| L (unpinned) | 16f63adb…f0bbcb8 · 100,758 B |
e913ff41188211c02d536da616337544e64133996cd7cc7a6521a8df1960226f · 101,375 B |
| A (pinned to L's seeds) | 16f63adb…f0bbcb8 · 100,758 B |
e913ff41…1960226f · 101,375 B |
| B (pinned to L's seeds) | 16f63adb…f0bbcb8 · 100,758 B |
724528ffde9a7514b69ab9e82ed3b8c8ade63d622c0720de30503a73a92df11e · 101,370 B |
state_checksum.py --floats bits --mask none, coverage: PROVED (1067776 bytes rebuilt == inflated); 61147 leaves, 333275 value bytes:
- pre-turn, A vs B:
IDENTICAL(root6bbaf382c9e570ae882b599f566ae62e). P2 held. - post-turn, L vs A:
IDENTICAL(root8100b28960f729ef9a24a22f13397b4a). P3 held — and it is the strongest single fact in this lane: a pinned process reproduced an unpinned run of a turn-27 build turn byte for byte. - post-turn, A vs B:
DIVERGED: 35 leaf difference(s). P1 falsified.
3.3 The 35 leaves, in full
All 35 are in verify/results/shim/bp/statecheck-AB.txt. They are:
| where | leaves | what |
|---|---|---|
/Sim/fleets/Flt[1970 "Sigma Fleet VI"] |
16 | FPlan (only-in-B), Pos[0..2], PrvPos[0..2], FtOrig[0..2], LocID 384→0, HFPlan F→T, FtTrans 0→1, FtFlg 12→13, ships/Ship[6976] only-in-A, ships/Ship[5264] only-in-B |
/Sim/fleets/Flt[1986 "Tau Fleet VI"] |
16 | exactly the same list with A and B exchanged |
/Sim/systems/Sys[384 "Ka'Trulmo"]/Flt[1] |
1 | 1970 → 1986 |
/Sim/ShipIDs[] |
1 | list-reordered (same set, different order) |
/Summary/Checksum |
1 | 643087964 → 643087980 |
Read it as one sentence: two newly created fleets swapped identities. In A, fleet 1970 is
the one sitting at Ka'Trulmo (system 384) holding Ship[6976] and fleet 1986 is the one in
transit (HFPlan true, FtTrans 1, a flight plan, an origin) holding Ship[5264]. In B it is the
other way round. Both fleets exist in both runs; both ships exist in both runs; the same system
holds a fleet in both.
What did not move, and this is the load-bearing half. Every leaf lane AD saw move outside this transposition is identical here:
/Sim/ModCount— AD had 1496 vs 1500; identical in A and B;/Sim/NumFlts,/Sim/DesignIDs[],/Sim/FleetIDs[]— AD had all three moving; identical;- Player[32]'s
ShipRecs,odes,designs,Sav,PvSav,Maint,FNGNum— AD had 41 leaves here; identical; - the AI build queues at
Sys[368]/BQandSys[272]/BQ— AD had 4 leaves; identical; - the four
turnstats/historyrows for player 32 — AD had 4; identical; /Sim/RNG(1e458a997f51bbdf) and/Sim/trdmgr— identical, as in AD.
94 leaves → 35, and the 35 are a permutation. The seed is responsible for the AI's choices; it is not responsible for the residue.
3.4 The command block: three words, and they are the same transposition
The aiorders dump gives the same statement from the input side, and it is sharper because this
lane has a noise mask that no previous lane could build for this state: runs L and A wrote
byte-identical autosaves, so by lane CB's argument (turncommands-capture.md §2) any word that
differs between L's and A's dumps cannot be a word the applier reads.
Structure first: 9 blocks and 81 elements in both runs, the same (pid, list, idx) sequence,
the same per-list counts — player 32 emits lists {1:3, 3:19, 5:15, 7:2, 8:3, 10:4, 12:12, 14:8, 23:15} in both. Every gate that is set agrees (rate=1:0.8 for 32/496/512, rate=1:1 for 16);
the target=0:<garbage> payloads differ and are the uninitialised-when-unset payloads lane L4
already documented as L4's P1 falsifier.
The L/A mask proves these (list, word) positions are noise: 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. Against that mask, A and B differ in three words of the entire block set:
list 8 idx=1 word0 (fleetId of a fleet-move command) A=1986 B=1970
list 10 idx=0 word0 (systemId) A=384 B=80
list 10 idx=1 word0 (systemId) A=80 B=384
List 10's fleet ids are in the same order in both runs — (·,1970) (·,1986) (·,2002) (·,7072).
What swaps is which system each of the first two is paired with. So the id counter is
deterministic and hands out 1970 then 1986 then 2002 in both processes; what varies is which
newly formed ship group each id lands on.
Two consequences worth stating plainly:
- The difference is upstream of, or inside, the AI's command emission — not downstream in the applier. The block already carries it.
- The design element is fully identical. List 1's only A/B differences (words 1 and 8) are in
the proven-noise set; the name bytes are identical, and the two designs decode to
"Egg Thief Mk 4"and"Bravestar Mk 3"in both runs. That extends the resolver's "the design content does not vary" from a comparison of two save bodies to a comparison of the commands that created them.
3.5 Things this lane checked and did not find
- No fourth AI client, no wildcard hit, no
pinned=0. A half-applied pin is excluded by the log, not by argument. - No encounter query in any of the three runs; End Turn ran to the post-turn autosave each time.
- The pre-turn autosave equals lane AD's
16f63adb…, on a different guest, a different build and a different config. That is an input-identity check on a file written before the AI runs; no conclusion about the AI is drawn from it, and per rule 19 and the resolution's own instruction no pinned file here is compared with any of AD's post-turn files. - Two defects in the mechanism this lane inherited, both in
src/shim/shim.cfg.cbpin— §2.2. And, reported because it is the same class of mistake: my own first draft ofshim.cfg.bppinreproduced the second one exactly (a wrapped header comment leaving a livehooks=trace…line in the body). It was caught before it was ever run, by diffing the two configs' non-comment lines against each other — which is the check that should be standard for anyshim.cfg.<tag>derived from another.
4. Verdict
Probe 2's prediction is falsified, and this is a resolution trigger, not a lane result. Per the resolution's own instruction ("if they differ, do not analyse — post the leaf diff and stop"), this lane localises and hands back. What follows is the localisation, stated as precisely as the evidence allows and no further.
-
Reading 3 is ALIVE on rich states. A per-process input other than the AI client seed reaches
ad-turn27 → 28. Two processes with identical pinned seeds, identical build, identical config, identical input save and identical pre-turn autosave produced different turn-28 states. -
C-exact must be restated, and the restatement is narrow. It is not "the AI is non-deterministic given the seed" — every decision is identical. It is:
Given (save, per-client seeds), the AI's command block is determined up to the assignment of newly allocated fleet ids to newly formed fleets. One residual per-process input decides that assignment, and it is not the seed.
A
game/aithat byte-matches will need either to reproduce that input or to canonicalise the assignment — and the second is available (a canonical order, the way L4's C-set recommends a canonical pick), which means Rung C is damaged but not lost. -
The residue has the exact shape the 09-08 resolution withdrew for the research pick and never re-tested elsewhere: a container walked in a different order. Same ids handed out in the same sequence; same fleets formed; different pairing. That is what a
std::map/std::setkeyed on a pointer, or a hash bucket ordered by address, produces under ASLR. It is inference, not measurement — this lane has not seen the container — and the resolver should treat it as the first hypothesis to shoot at, not as a finding. -
The pin is not useless — it is most of the answer. It removed 59 of AD's 94 leaves and every substantive decision: the design, the build queues, the research, the money, the ship records,
ModCount,NumFlts,DesignIDs[],FleetIDs[]. Row 360's claim survives with a scope, and the character of the residual is completely different from the thing the seed explains. -
Rule 26 corollary (c), applied honestly. My control is the A/B pinned pair and it does not agree with itself, so by rule 26 it certifies nothing and exonerates nothing. What carries evidential weight instead is the L/A pair, which does agree, byte for byte, across two processes — and it certifies exactly:
(ad-turn27-two-raiders.sav, load → one End Turn,shim.cfg.bppinwith seeds32=156ebbbd,496=fe7b2826,512=0ed341d1, buildbp-989c692-20260909T0505Z) → pre16f63adb…, poste913ff41…`` — reached by two of three processes, with the exposure facts of §3.2 on the same line. Two of three is a1/kresult on ak ≥ 2workload and is NOT an oracle pair. It is recorded as a procedure that has been reached twice, nothing more. -
What this probe still cannot decide (§1.2 stands): the 3–40-turn fuse at
0x0069dbb0cannot fire inside one turn of a load and is untested here; and nothing here speaks about the un-instrumented game, because a pin cannot be applied without hooks.
4.1 The next probe, named but deliberately not run
The obvious one, and it is one load: a third pinned process, run C. If C lands on A's file the
residual input has a small outcome set and A/L is the modal branch; if it lands on a third file the
set is larger. That is 12 minutes and it is a resolver's call, not this lane's — the brief says
localise and hand back, and running C would be the start of the follow-up analysis this lane was
told not to do. Two further candidates, in the order I would rank them: (i) lane Z's per-client
draw ledger keyed on this (probe 3), which would show whether the two fleet-creation sites draw
at all — if they do not, the ordering is not an RNG effect and the container hypothesis is the only
one left; (ii) a hook on whatever enumerates the completed-ship groups, recording the container's
first two elements' addresses — one run tells you whether the order tracks addresses.
Proposed board rows
New row:
| PINNED SEEDS DO NOT COLLAPSE A RICH TURN - C-exact is false on ad-turn27, and the residue is ONE FLEET-ID TRANSPOSITION | control-flow | verified | high | 100% | 2026-09-09 | Lane BP, VM146, probe 2 of the 2026-09-09 resolution (`findings/control-flow/pinned-seed-rich-turn.md`). Build `bp-989c692-20260909T0505Z`, fresh CT111 tree (rule 24), lane worktree (rule 21). THREE fresh processes on `ad-turn27-two-raiders.sav` (1c8baa27...), one End Turn each, lane CB's CONSTRUCTOR-ARGUMENT overwrite (`aiseed=pin`, NOT `airng.pin_seed`), every template hook off BY NAME (27 reported `mode=off`), zero unknown keys, zero COVERAGE lines, `aiseed call=1/2/3 pinned=1` in both pinned runs. **THE BRIEF WAS WRONG ABOUT THE PLAYER COUNT: the save has seven non-human players and the engine builds THREE AI clients** - RunAI fires exactly 3x, net ids 32/496/512; 528 Alien Menace, 544 Peacekeeper Enforcer, 560 Von Neumann and 576 Independent Colony get no client, no call and no seed. Nine distinct natural seeds across three processes, none shared (L1's per-process seeding, reproduced a 4th time on a turn-27 state). RESULT: **run L (unpinned) and run A (pinned to L's observed seeds) are BYTE-IDENTICAL** (`e913ff41...`, state_checksum IDENTICAL, 61147 leaves, coverage PROVED) - a pinned process reproduced an unpinned run of a rich build turn. **Run B, same pinned seeds, fresh process, DIFFERS: `724528ff...`, 35 leaves.** So P1 IS FALSIFIED and READING 3 IS ALIVE: a per-process input that is NOT the seed reaches a rich turn. **BUT THE PIN DID ALMOST ALL OF THE WORK.** AD's UNPINNED pair on the same save differed in 94 leaves across designs, ShipRecs, Sav/Maint/PvSav/FNGNum, both AI build queues, ModCount (1496 vs 1500), NumFlts, DesignIDs[], FleetIDs[] and four turnstats rows. BP's PINNED pair differs in 35, and ALL 35 ARE ONE TRANSPOSITION: fleets **1970 "Sigma Fleet VI"** and **1986 "Tau Fleet VI"** exchange their entire contents (Pos, PrvPos, FtOrig, FPlan, LocID 384<->0, HFPlan, FtTrans, FtFlg 12<->13, Ship[6976]<->Ship[5264]), plus Sys[384]/Flt[1] 1970->1986, /Sim/ShipIDs[] list-reordered and /Summary/Checksum. **ModCount, NumFlts, DesignIDs[], FleetIDs[], every build queue, every design, every ship record and /Sim/RNG are IDENTICAL.** The AI command block says the same thing from the input side: 9 blocks / 81 elements, same (pid,list,idx) sequence, same per-list counts, and - masked by the noise set the byte-identical L/A pair PROVES (list 1 w1,5,8,11; list 3 w4-11; list 5 w8-11; list 7 w2-11; list 8 w1-11; list 10 w2-11; list 12 w5-11; list 14 w2-11; list 23 w2-11) - **EXACTLY THREE WORDS DIFFER**: list 8 idx1 word0 fleetId 1986/1970, list 10 idx0 word0 systemId 384/80, list 10 idx1 word0 systemId 80/384. List 10's fleet ids are in the SAME order in both (1970, 1986, 2002, 7072), so the id counter is deterministic and what varies is WHICH NEWLY FORMED SHIP GROUP EACH ID LANDS ON. Design elements identical including the name bytes ("Egg Thief Mk 4", "Bravestar Mk 3"). **C-EXACT RESTATED: given (save, per-client seeds) the AI's command block is determined UP TO the assignment of newly allocated fleet ids to newly formed fleets; one residual per-process input decides that assignment and it is not the seed.** Rung C is damaged, not lost - the assignment is canonicalisable the way L4's C-set canonicalises a pick. INFERENCE, NOT MEASUREMENT: the residue has the shape of a container walked in pointer order under ASLR - the reading the 09-08 resolution withdrew for the research pick and never re-tested on a build turn. RULE 26 (c): the A/B control does NOT agree with itself, so it certifies nothing; the L/A pair does, and certifies only (save, procedure, hashes) reached by two of three processes - a 1/k result, NOT an oracle pair. Exposure facts on the same line: Player[32] ResTNm=BIO_TerBac HELD, NumDes 46, NumOwn 15, 13 ships completing; 496/512 hold targets with NumOwn=0/NumDes=0; the four NPC factions have ResTNm=='' AND NumOwn==0 AND NO AI CLIENT. NEXT: one more pinned process (run C) sizes the residual outcome set; probe 3's per-client draw ledger says whether the fleet-creation sites draw at all. Artefacts: `verify/results/saves/bp-{pinA,pinB}-turn28.sav`, `bp-turn28-pre.sav`, `verify/results/shim/bp/` |
Edits to existing rows:
- Row 360 — replace the scope note queued by the resolver with:
SCOPE, MEASURED 2026-09-09 (lane BP): proved on turn1-state (early game); on the rich turn ad-turn27 pinning does NOT collapse two processes to one. It collapses 94 leaves to 35, and the 35 are a single fleet-id transposition with every decision leaf identical. Pinning explains the AI's CHOICES on a rich turn; it does not explain the ORDER in which two new fleets are matched to their ids. - Row 415 (AD's oracle row) — append:
PARTLY EXPLAINED 2026-09-09 (lane BP, VM146): with the three AI client seeds pinned, 59 of AD's 94 leaves go away - ModCount, NumFlts, DesignIDs[], FleetIDs[], both build queues, every design and ship record and all four turnstats rows become identical. The 35 that remain are fleets 1970 and 1986 exchanging contents. So AD's attribution "the per-process AI seed" is RIGHT for the substance of the variation and INCOMPLETE: a second, non-seed per-process input orders the fleet-id assignment. - Row 326 — append:
And it is not the whole story on rich turns: lane BP pinned it on ad-turn27 and two processes still differed - by a fleet-id transposition and nothing else (2026-09-09). - Row 333 / the Rung C row — append:
C-EXACT FALSIFIED ON A RICH TURN 2026-09-09 (lane BP): restated as "determined up to the assignment of newly allocated fleet ids to newly formed fleets". Damaged, not lost - the assignment is canonicalisable. - Row 62 — VM146: lane BP held it 2026-09-09 01:05-02:0x local for probe 2, and released it restored: pre-BP autosaves restored byte-identical from
C:\SOTS\ui\preBP\,ad-turn27-two-raiders.savleft on disk (so the Load-dialog rows have MOVED: with the autosaves deleted the list is 7 rows from y=260 at 29 px pitch,ad-turn27-two-raidersis row 1 at (400,260)),shim.cfgandbinkw32.dllrestored to the pre-BP files, main menu verified by screenshot. LeftC:\SOTS\shimdist-bp+C:\SOTS\ui\bp{deploy,shot,hash}.ps1+C:\SOTS\ui\preBP\;click_helper.ps1untouched. GOTCHA, AND IT COST THIS LANE FOUR WASTED CLICKS: the lab wall's/shot/<id>.pngserves a CACHED frame and can be a whole poll cycle (~5 s) BEHIND your last action. Clicking a Load-dialog row and screenshotting 5 s later showed the row un-selected; a second click showed it selected - which reads exactly like "the click was swallowed" and is not. Wait ~12-16 s before reading the frame, or take two shots and use the second. One click selects a row; one click works the OK button. Startup on this guest confirmed at ~2 min (fg+key {ESC}x3 spaced 2.5 s, then ~90 s); loading the turn-27 save is a further 3.5-4 min and is not compressible; End Turn on it took ~35 s with the light hook set.
Docs to correct in place (rule 11), proposed, not done by this lane:
determinism-oracle.md— the "Qualified" section should record that pinned seeds do not make a rich turn reproducible, and that the residual is a fleet-id assignment.src/shim/shim.cfg.cbpin(sots-engine) — add the six missinghook.*=offlines and fix the wrapped header comment on line 4 (§2.2). Lane CB's result is unaffected; the file is a trap for the next lane to copy it.