163 lines
9.7 KiB
Markdown
163 lines
9.7 KiB
Markdown
# 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.)*
|