From d98f435017f11dc45398b5726c771bc56ff05116 Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 8 Sep 2026 21:58:50 -0400 Subject: [PATCH] AD: predictions for the trade-raid multiplicity probe, committed before the build --- .../control-flow/raid-gate-multiplicity.md | 163 ++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 findings/control-flow/raid-gate-multiplicity.md diff --git a/findings/control-flow/raid-gate-multiplicity.md b/findings/control-flow/raid-gate-multiplicity.md new file mode 100644 index 0000000..c99d5c2 --- /dev/null +++ b/findings/control-flow/raid-gate-multiplicity.md @@ -0,0 +1,163 @@ +# Trade-raid gate multiplicity — does the tail draw once per turn, or once per qualifying fleet? + +- **Type:** control-flow (static decode + live measurement) +- **Status:** **predictions committed, not yet measured** — this header block is replaced when the + run lands +- **Owner / date:** lane AD · 2026-09-08 · guest **VM141** (`sots-re-win10-b`, 192.168.10.143) +- **Follows:** the resolution `findings/resolutions/2026-09-09-tail-draws.md` §4 (the one probe), + lane AC's `findings/control-flow/trade-raid-rng-gate.md` +- **Instrument:** lane Z's return-address ledger (`draw_sites`) + lane H's entry probes at + **`probes=8`** — the configuration lane H bisected as byte-neutral. **Not `probes=11`.** + +--- + +## 1. Predictions, committed before the build (rule 2) + +Written on the host, before the shim was built, before the workload was played and before any +counter was read. What follows in §1 is frozen; everything after it is the run. + +### 1.0 The callee, decoded in full first + +Lane AC read the *caller* (`ServerTradeManagerImpl::vslot13`, `0x0088ef80`) and reported the +short-circuit inside the callee from a partial read. This lane decompiled the whole of +`TradeManager::Slot13RngCalleeA` `0x00820ca0` (436 bytes, 89 decompiled lines, both the loop and +its converge point visible — rule 4), because the prediction depends on where the draw sits +relative to the loop. Transcribed to a model: + +``` +A(fleet, freighterInSector) -> bool: + if fleet == null: return false # 0 words + n = (fleet+0xa8 - fleet+0xa4) / 4 # ship vector count + if n <= 0: return false # 0 words + anyBig = OR over ships of ( *(design + 0x12c) > 1 ) + allSuppressed= AND over ships of ( ship+0x18 & 0x80 ) + nDE = #{ ships : !(flags & 0x80) and *(design+0x12c) == 0 } + nCR = #{ ships : !(flags & 0x80) and *(design+0x12c) == 1 } + bestScale = max over ships of ( (flags & 0x100000) ? K : 1.0 ) # K a float global + if anyBig: return TRUE # 0 words <-- short-circuit + if allSuppressed: return false # 0 words + odds = (nCR >= 1 ? ODDS_CR : (nDE > 0 ? ODDS_DE : 0.0)) + (nCR + nDE) * PER_SHIP + if freighterInSector: odds = odds + odds + r = NextFloat() # <-- EXACTLY ONE WORD + return (odds * bestScale > r) +``` + +Three consequences that the measurement is against: + +1. **The draw is inside the callee, and the callee is called once per fleet.** So the word cost of + the site is `Σ over fleets passing G0–G4 of (0 if short-circuited or shipless or all-suppressed, + else 1)`. Not a per-sector constant. +2. `design + 0x12c` takes the values **0, 1 and >1** and is used to bucket ships into two counted + classes plus a third that short-circuits. That is a **hull class** field, and lane AC's fleet — + one `Repair and Salvage`, built with `IND_CruisCon` — is the `== 1` bucket. `> 1` is therefore + the next hull up (a dreadnought, if the ordering is DE/CR/DN), which this game has not + researched. +3. There is exactly **one** `NextFloat` on the path, with no rejection loop around it, so a fleet + that reaches the roll costs exactly one word — never two. + +### 1.1 The state this lane will build + +From `verify/results/saves/ac-turn22-raider.sav`, read on the host before touching the guest: + +| field | value read | +|---|---| +| player 0 | `PlryName "re"`, `PlyrIdx 0`, `HomeSys 48`, `Sav 63,032,174`, `CnRad true` | +| player 0 fleets | **exactly one**: `FltID 3744` `"Alpha Fleet"` `PID 16`, `NShips 1`, `LocID 832`, `Pos [0, 0, 8.0]`, `FtFlg 4`, ship `DesID 17` (`Repair and Salvage`, `IND_CruisCon`) | +| sector 6 | `TradeID 832`, `tsgridID 6`, `Pos [0, 0, 8.0]`, `tssec 0`, **`tsct 0`**, **`tscr 253`**, `tsnumsys 4` (`tssys` 256, 416, **48**, 96), `tsnumflt 1`, `tsflt 3744` | +| all six sectors | `tscr 253` / `ptscr 253` | +| player 0 designs | `Armor`, `Tanker`, `Colonizer`, `Extended Range`, `Light Defense Platform`, `Repair and Salvage` (`DesID 17`), `Default Assault Shuttle` | + +Sector 6 contains the home system (48), `tsct` is 0 so the `FtFlg & 0x800` conjunct is not armed, +and `tscr` bit 0 is set. Every conjunct of the gate is already satisfied for a **second** fleet +parked on the same node. + +**The workload:** build one more `Repair and Salvage` cruiser at system 48, keep it as its own +fleet, order it to the sector-6 node, and confirm `LocID 832` + `Pos` bit-equality **from the +autosave, not the panel** (lane AC's gotcha). That makes two single-cruiser fleets on one sector. + +**Deliberate deviation from the brief, stated up front.** The brief and the resolution §4 ask for a +second raider *of a hull satisfying `design+0x12c > 1`*, to price the short-circuit. §1.0 shows that +field is a hull class and `> 1` means a hull above cruiser, which this game has not researched and +cannot research and build inside five turns. Pricing the short-circuit is also the *second* question; +the first is multiplicity, and a second **cruiser** answers it with the cleanest possible signal — +under H-fleet the word count doubles, under H-sector it does not move. A dreadnought would leave the +word count at 1 under both hypotheses and force the entry counter to carry the whole result alone. +So: second cruiser, and the short-circuit stays unpriced. Recorded as a gap, not skipped. + +### 1.2 P1 — H-fleet (primary) + +**With two single-cruiser fleets on sector 6, `TradeManager::Slot13RngCalleeA` is entered `2` times +per End Turn and `StrategyServer::OnAllCombatDone_Tail` costs `2` strategic words per turn**, against +lane AC's `1` and `1` on the same lineage with one fleet. + +Confidence: **high**, on §1.0 plus lane AC's read of the caller's loop over +`StrategyServer+0x64..+0x68`. + +*Falsification and symptom.* `calls = 1` on the `TradeManager::Slot13RngCalleeA` probe row with two +fleets confirmed on the node kills it, and P2 is then the answer. + +### 1.3 P2 — H-sector (the hypothesis this lane exists to kill) + +If the roll is per *sector* and not per *fleet*, `Slot13RngCalleeA` is entered `1` time and the tail +costs `1` word with two fleets exactly as with one. + +Confidence: **low**. It is stated because four lanes have now been wrong about this call site by +reasoning rather than measuring, and because a `1` here would mean §1.0's model — and therefore the +generator model the standalone is about to gain — is wrong about the loop. + +### 1.4 P3 — per-site attribution + +`draw_sites` reports exactly **one** strategic-generator row inside the callee's body, entry kind +`NextFloat`, `ret_rva` in `0x00420ca0..0x00420e53`, with `calls == words == 2` and +`no_draw_calls == 0`. The site sum for the tail bracket equals the boundary ledger's tail delta. + +Confidence: **high** on the row existing and on the equality; **moderate** on `calls == 2`, because +that is P1 restated through the other instrument. The two instruments disagreeing is itself the +interesting outcome and would be reported as one. + +### 1.5 P4 — `Slot13RngCalleeB` and its inner `NextInt` + +`B` is entered once per fleet whose roll **succeeded**, so `0`, `1` or `2` times per turn, and it +costs **0 words** on every entry — i.e. **no** strategic `draw_sites` row inside +`0x0048b440..0x0048b976`. + +Confidence: **low-to-moderate**. "0 words" rests on lane AC's single observation and the resolution +itself flags the gate above that `NextInt` as unread (§3.1's unfilled rows). A row appearing there is +a **result**, not a failure: it prices a site the gate-indexed audit currently has to leave blank. + +### 1.6 P5 — the oracle pair + +Two `hooks=off` runs of the same End Turn from the same input save, in two fresh processes, produce +**byte-identical** `(Autosave EndTurn).sav` and `(Autosave).sav`. + +Confidence: **moderate, and this is the prediction most likely to fail.** Rule 26's counter-example +is exactly this shape: three `hooks=off` runs on `turn1-state` gave three different files, pinned to +a per-process AI seed. That save has three AI empires; this one has **seven**, at turn 22, all of +them making research and build choices every turn. If the pair does not agree I will localise the +difference to named leaves with the state-checksum tool, report whether it is confined to the known +AI-seed leaves, and — if it is not — say plainly that **no oracle pair exists for this state** and +that the numbers in §3 are entry counts and word deltas rather than calibration data. Rule 26: a +control that does not agree with itself exonerates nothing. + +### 1.7 P6 — instrument neutrality on this state (rule 19) + +The `(Autosave).sav` produced by the `probes=8` run is byte-identical to the `hooks=off` oracle +above. This is lane H's `probes=8` neutrality claim re-tested on a state it was never tested on, +and it costs nothing to check because both files exist anyway. + +Confidence: moderate. Conditional on P5: if the control does not agree with itself, this comparison +means nothing and will not be reported as evidence (rule 26's second half — agreeing with one run of +a varying control is a `1/k` coincidence). + +### 1.8 What would make this lane report a zero (rule 28) + +If `Slot13RngCalleeA` is entered `0` times, the failed conjunct will be named from the save, not +guessed. The four to read on the post-move autosave are: `Flt.LocID == 832` for **both** fleets; +`Flt.Pos` bit-equal to `Trade.Pos` `[0, 0, 8.0]` for both; `tscr` bit 0 still set (`253`); and +`tsct` still `0` on sector 6 — because if the AI starts trading through sector 6 during the five +turns, `tsct` bit 0 arms the `FtFlg & 0x800` conjunct and **both** fleets fail it, taking the site +back to zero for a reason that has nothing to do with multiplicity. + +--- + +*(Sections 2 onward are written after the run.)*