diff --git a/findings/control-flow/raid-gate-multiplicity.md b/findings/control-flow/raid-gate-multiplicity.md index c99d5c2..e98f4d0 100644 --- a/findings/control-flow/raid-gate-multiplicity.md +++ b/findings/control-flow/raid-gate-multiplicity.md @@ -1,28 +1,55 @@ -# Trade-raid gate multiplicity — does the tail draw once per turn, or once per qualifying fleet? +# Trade-raid gate multiplicity — the tail draws **once per qualifying fleet**, and `B` returns without drawing -- **Type:** control-flow (static decode + live measurement) -- **Status:** **predictions committed, not yet measured** — this header block is replaced when the - run lands +- **Type:** control-flow (full static decode of the callee + live measurement) +- **Status:** **verified** for the multiplicity claim and for `B`'s zero cost on sector 832; + **not run** for the sector-816 reachability probe (§6 says why, with the numbers) +- **Confidence:** high on the counts (two turns, one process, reproduced turn-to-turn; the control + agrees bit-for-bit on the sub-tree the measurement reads — §5) - **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`.** + **`probes=8`** — the byte-neutral set. **Not `probes=11`.** Shim build + `ad-0c6d0a3-20260909T0159Z`, config `src/shim/shim.cfg.hp8` **unmodified**. +- **Follows:** `findings/resolutions/2026-09-09-tail-draws.md` §4; lane AC's + `findings/control-flow/trade-raid-rng-gate.md`; lane AG's + `findings/control-flow/gate-indexed-rng-audit.md` §3.3 + +--- + +## 0. Headline + +> **The trade-raid roll is per **fleet**, not per sector, and the word cost scales linearly.** +> With **two** permitted raiders parked on sector 6 instead of lane AC's one, +> `TradeManager::Slot13RngCalleeA` is entered **2×** per End Turn and +> `StrategyServer::OnAllCombatDone_Tail` costs **2** strategic words — against AC's **1** and **1** on +> the same lineage, the same guest and the same build. Reproduced on two consecutive turns. +> The return-address ledger prices the site exactly: `0x00820e18`, **calls = 2, words = 2**, on both +> turns. H-sector is dead. + +> **And `Slot13RngCalleeB` fired once, at zero words — a second, independent confirmation of lane +> AG's §3.3 diagnosis.** `RNG_NextInt` has no zero-bound early-out, so a `B` that costs nothing +> never reached its target pick. On sector 832 that is the candidate list being empty, and my +> two-fleet state reproduces it with a fleet lane AC never had. + +> **There is no oracle pair for this state, and I am not going to pretend otherwise (rule 26).** +> Two `hooks=off` runs in two fresh processes produced **different** post-turn autosaves — 94 leaves +> apart. But the difference is **entirely** the AI empire's design/build/fleet decisions, and +> `/Sim/RNG`, `/Sim/trdmgr` and every player-0 fleet are **bit-identical across all three processes**, +> instrumented and not. §5 gives the digests. Every number in §3 is read off that reproducible +> sub-tree; none of them is read off a leaf that moved. --- ## 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. +Committed in `d98f435` before the shim was built, before the workload was played and before any +counter was read. Reproduced verbatim below with the verdicts added. ### 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: +Lane AC read the *caller* 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, loop and converge point both visible — rule 4), because the prediction depends on where the +draw sits relative to the loop: ``` A(fleet, freighterInSector) -> bool: @@ -33,7 +60,7 @@ A(fleet, freighterInSector) -> bool: 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 + bestScale = max over ships of ( (flags & 0x100000) ? K : 1.0 ) 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 @@ -42,122 +69,410 @@ A(fleet, freighterInSector) -> bool: return (odds * bestScale > r) ``` -Three consequences that the measurement is against: +Three consequences the measurement was 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. **The draw is inside the callee and the callee is called once per fleet**, so the site's cost is + `Σ over fleets passing G0–G4`, not a per-sector constant. +2. `design + 0x12c` takes values 0, 1 and >1 and buckets ships into two counted classes plus a third + that short-circuits — a **hull class** field. AC's `Repair and Salvage` (`IND_CruisCon`) is the + `== 1` bucket, so `> 1` is a hull above cruiser. +3. There is exactly **one** `NextFloat` on the path with no rejection loop, so a fleet that reaches + the roll costs exactly one word — never two. -### 1.1 The state this lane will build +**The constants, read out of the image afterwards** (rule 23 — read the four bytes, and these are +all **widened floats**, not decimals): -From `verify/results/saves/ac-turn22-raider.sav`, read on the host before touching the guest: +| symbol | address | bytes | value | +|---|---|---|---| +| `ODDS_CR` | `0x009e20d8` | `00 00 00 A0 99 99 C9 3F` | `(double)0.2f` = **0.20000000298023224** | +| `ODDS_DE` | `0x009e5060` | `00 00 00 A0 99 99 A9 3F` | `(double)0.05f` = **0.05000000074505806** | +| `PER_SHIP` | `0x009e31c0` | `00 00 00 40 E1 7A 84 3F` | `(double)0.01f` = **0.009999999776482582** | +| `K` (flag `0x100000`) | `0x009f8d48` | `C3 F5 A8 3E` | float **0.33** — it *reduces* the odds | -| 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` | +This confirms AC's `0.20 / 0.05 / +0.01·nShips` read for **this** function (AC quoted the same two +decimals for `GenerateTradeRaidEncounters`, a different site; they happen to agree) and adds the +per-ship scale, which had not been valued. **A one-cruiser fleet's odds are +`0.20000000298023224 + 0.009999999776482582 = 0.21000000275671482`, times 1.0, not doubled** — +sector 832 holds no freighter. -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. +### 1.1 The state, read from the save before touching the guest -**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. +`verify/results/saves/ac-turn22-raider.sav`: player 0 `re`, `PlyrIdx 0`, `HomeSys 48`, +`Sav 63,032,174`, `CnRad true`; **exactly one** player-0 fleet (`FltID 3744` `"Alpha Fleet"`, +`NShips 1`, `LocID 832`, `Pos [0, 0, 8.0]`, `FtFlg 4`, `DesID 17`); sector 6 = `TradeID 832`, +`tsgridID 6`, `Pos [0, 0, 8.0]`, `tssec 0`, **`tsct 0`**, **`tscr 253`**, `tsnumsys 4`, +`tsnumflt 1`; all six sectors `tscr 253`. -**Deliberate deviation from the brief, stated up front.** The brief and the resolution §4 ask for a +**The workload built:** one more `Repair and Salvage` cruiser at system 48, kept as its own fleet, +ordered to the sector-6 node — two single-cruiser fleets on one sector. + +**Deliberate deviation from the brief, stated up front.** The brief and resolution §4 asked 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. +field is a hull class and `> 1` means a hull above cruiser. **The Build screen's Dreadnought category +is empty in this game** (screenshot `b4`), so no such hull exists to build, and pricing the +short-circuit is the *second* question anyway. A second **cruiser** answers the first with the +cleanest signal: under H-fleet the word count doubles, under H-sector it does not move. The +short-circuit stays unpriced — recorded as a gap in §7, not skipped. -### 1.2 P1 — H-fleet (primary) +### 1.2–1.8 The predictions, with verdicts -**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. +| # | prediction | verdict | +|---|---|---| +| **P1** | H-fleet: with two single-cruiser fleets, `Slot13RngCalleeA` entered **2×/turn** and the tail costs **2 words/turn** | **CONFIRMED**, both turns (§3) | +| **P2** | H-sector: `A` entered 1×, tail 1 word regardless of fleet count | **FALSIFIED** — as intended; this is the hypothesis the lane existed to kill | +| **P3** | `draw_sites` shows exactly one strategic row inside the callee body, `NextFloat`, `ret_rva` in `0x00420ca0..0x00420e53`, `calls == words == 2`, `no_draw_calls == 0`, and the site sum equals the boundary ledger's tail delta | **CONFIRMED exactly** — row at call `0x00820e18`, calls 2, words 2, both turns; bracket residual 0 | +| **P4** | `B` entered once per succeeding fleet (0–2×/turn) and costs **0 words** — no strategic row in `0x0048b440..0x0048b976` | **CONFIRMED as a number, and its *meaning* was wrong in my brief.** `B` entered 1× / 0× on the two turns and cost 0 words both times. Lane AG (posted after this prediction was committed) read all 139 bytes of `RNG_NextInt` and found **no zero-bound early-out**, so `B` cannot reach its pick without spending a word. `B` costing 0 therefore **proves `B` returned before the pick** — it is not a cheap success, it is a non-success. My predicted number was right for the wrong reason and I am recording that plainly. | +| **P5** | two `hooks=off` runs in two fresh processes give byte-identical autosaves | **FALSIFIED.** I flagged it as the most likely failure and it failed. §5. | +| **P6** | the `probes=8` post-turn autosave is byte-identical to the `hooks=off` oracle | **Unanswerable as stated** (P5 failed, so there is no oracle to compare to), **and answered in a better form**: the instrumented run and both control runs are bit-identical on every sub-tree except the AI's decisions. §5. | +| **P8** | if `A` reads 0, name the failed conjunct from the save | not triggered; the conjuncts were read anyway (§4) | --- -*(Sections 2 onward are written after the run.)* +## 2. What was run + +Four fresh processes on VM141, all with the same guest, the same dist +(`C:\SOTS\shimdist-ad`, `BUILD_ID ad-0c6d0a3-20260909T0159Z`, built in +`/srv/re-lab/build/sots-engine-ad` after `rm -rf` of the tree and with no local `build*` shipped — +rule 24) and the same input save. + +| run | config | End Turns | purpose | +|---|---|---|---| +| play-forward | `shim.cfg.hoff` | 4 (turn 23 → 27) | build the workload | +| **R1** | `shim.cfg.hp8` (`probes=8`) | 2 (turn 27 → 29) | the measurement | +| **OA** | `shim.cfg.hoff` | 1 (turn 27 → 28) | control | +| **OB** | `shim.cfg.hoff` | 1 (turn 27 → 28) | control, second fresh process | + +Input save `ad-turn27-two-raiders.sav`, sha256 +`1c8baa27680809d585ab1728391e82729642d32aaedffd5bf95b616f0a11a436`. It is the post-turn autosave of +turn 26, produced by ordinary play from `ac-turn22-raider.sav`: queue two `CR Repair and Salvage`, +End Turn ×2, form the first completed hull into `Beta Fleet`, `Move` → sector-6 node, End Turn ×2. + +**Instrument armed and verified from `shim.log`, not assumed:** all seven `drawsite:` detours +`create=MH_OK enable=MH_OK`; `probe: installing 8 of 12 (probes= in shim.cfg)` and all eight +`create=MH_OK enable=MH_OK`. Probe indices 8–11 report **NOT INSTALLED**, never 0 (rule 1) — index 8 +is `GenerateTradeRaidEncounters`, the detour lane H bisected as *not* byte-neutral, and it is +excluded by construction. + +**The gate, read from the save for the measured turns** (rule 28 — the field values, not a summary). +From R1's own post-turn autosave at turn 29: + +| conjunct | field | value | +|---|---|---| +| G2 fleet at a `TradeSector` node | `Flt["Alpha Fleet"].LocID` / `Flt["Beta Fleet"].LocID` | **832 / 832** | +| G3b owner's bit in the raid mask | `Trade[832].tscr` | **253** = `0b11111101`, bit 0 = player 0 ✓ | +| G3c `FtFlg & 0x800` armed? | `Trade[832].tsct` | **0** → not armed; neither fleet carries `0x800` (`FtFlg` 4 and 4) | +| G4 arrived, `Pos` bit-equal | `Flt.Pos` vs `Trade[832].Pos` | both **`[0, 0, 8.0]`**, bit-identical | +| — | `Trade[832].tsnumflt` / `tsflt` | **2** / **3744, 6544** | + +--- + +## 3. The numbers + +### 3.1 Entry counts (`probes=8`, R1) + +| probe | turn 28 | turn 29 | lane AC, one raider | +|---|---|---|---| +| `ServerSpyManager::vslot13` | 1 | 1 | 1 | +| `ServerSpyManager::vslot14` | 1 | 1 | 1 | +| `ServerTradeManagerImpl::vslot13` | 1 | 1 | 1 | +| `ServerTradeManagerImpl::vslot15` | 1 | 1 | 1 | +| `SpyManager::Slot13RngCallee` | 0 | 0 | 0 | +| **`TradeManager::Slot13RngCalleeA`** | **2** | **2** | **1** | +| **`TradeManager::Slot13RngCalleeB`** | **1** | **0** | 1 then 0 | +| `ServerTradeManager::CreateRaidEncounter` | 1 | 2 | 0 then 1 | +| indices 8–11 | NOT INSTALLED | NOT INSTALLED | — | + +`vslot13` is still entered **once** per turn while `A` is entered **twice**: the multiplicity is +inside the callee's caller loop over the fleet vector, exactly as AC read it. That is the cleanest +possible separation of H-fleet from H-sector — one instrument row moves, the other does not. + +### 3.2 The boundary ledger + +``` +turn 28 BeginProcessTurn 575 -> 575 delta 0 + ProcessTurn 575 -> 593 delta 20 + OnAllCombatDone_Tail 593 -> 595 delta 2 + BRACKET total 22 attributed 22 residual 0 + +turn 29 BeginProcessTurn 595 -> 595 delta 0 + ProcessTurn 595 -> 615 delta 20 + OnAllCombatDone_Tail 615 -> 617 delta 2 +``` + +**Two words per turn in the tail, on both turns.** Lane AC's control (no raider) was 0; AC's active +state (one raider) was 1; two raiders give 2. The bracket residual is **0** on turn 28, so nothing +else moved. + +### 3.3 Per-site attribution by return address (`draw_sites`) + +Turn 28, strategic rows only (helper-internal rows and other generators elided; the report tool +marks them): + +``` + * NextFloat call 0x0050329d calls= 1 words= 1 + * Chance call 0x00753d87 calls=14 words= 0 + * NextInt call 0x007929a4 calls= 1 words= 1 + * NextFloat call 0x00820e18 <-- the raid roll calls= 2 words= 2 + * Chance call 0x00893426 GenerateTradeRaidEncounters calls= 8 words= 8 + * Chance call 0x00893513 GenerateTradeRaidEncounters calls= 8 words= 8 + => attributed strategic words: 20 +``` + +Turn 29 is the same plus `ProcessResearch+0x1c8` (1 word) and a `NextFloat` at call `0x0088df4f` +(1 word) — two sites inside `ProcessTurn`, not the tail; **`0x00820e18` is again calls = 2, words = 2**. + +**`0x00820e18` is lane V2's site**, listed in `indirect-edges.md` §3.1 as trade slot 13's `NextFloat`, +fired once by lane AC and now priced at **one word per qualifying fleet**. + +**No strategic row anywhere in `0x0088b440..0x0088b976`** on either turn, and none in +`ServerTradeManager::CreateRaidEncounter`'s body on the turn it ran twice. So `B` cost 0 and +`CreateRaidEncounter` cost 0 — both by return-address attribution, not by a word count that could +have hidden them. + +### 3.4 The odds arithmetic, first measured support + +Two fleets × two turns = **four fleet-rolls** at `p = 0.21000000275671482` (one cruiser, no +freighter in sector 832, `bestScale` 1.0). Expected successes 0.84; **observed 1** (turn 28's single +`B` entry). Lane AC's two rolls at the same `p` gave 1. Six rolls, two successes, expectation 1.26 — +consistent, and stated as consistency rather than validation: six Bernoulli trials cannot +distinguish 0.21 from 0.15 or 0.30. + +--- + +## 4. What this settles about `Slot13RngCalleeB` — a verdict on lane AG §3.3 + +Lane AG's §3.3 posted while this lane was measuring. Two of its results bear directly on my numbers: + +1. **`RNG_NextInt` (`0x004271c0`) has no zero-bound early-out.** A single-candidate list still costs + one word. +2. `FUN_00820af0`, called at `0x0088b62c` right after the pick, draws again at `0x00820c1b`. + +So a `B` that costs **0 words** did not reach `0x0088b613`. My turn 28 has `B` entered once and the +tail's whole cost accounted for by `A`'s two words — **`B` returned before its pick, on a fleet lane +AC never had, on the same sector.** That is an independent reproduction of AG's diagnosis rather +than a re-reading of AC's single observation. + +**Which conjunct failed, from the save.** `trdmgr` at turn 27 and again at turn 29 holds **three** +route records, `trfr = 18, 14, 14` (`tro = 32`, the AI, on all three). Resolving each source system +to the sector whose node it sits nearest: system 18 (`Ko'Kotan`, `[9.56, 0.06, 2.27]`) → sector +**816** at 2.20 ly; system 14 (`Ko'Graapa`, `[1.44, 1.42, -2.22]`) → sector **768** at 2.03 ly. +**No route is sourced in sector 832.** So `G_B1b` (`containingSector[rt->trfr] == sector`) rejects +all three routes and the candidate list is empty — `G_B4`. + +**What my run does *not* settle, and I want this said clearly.** AG flagged one unproven reading: +that `TradeManager+0x0c` is a **per-system** "containing trade sector" table, versus a +**sector-indexed vector of six**, in which case `trfr ∈ {14, 18}` fails the bounds check `G_B1a` and +`0x0088b613` is unreachable in principle. **My measurement cannot distinguish those two readings**, +because on sector 832 both of them predict exactly what I saw: `B` entered, `B` returns before the +draw. The experiment that separates them is a raider parked on a sector that *does* source a route, +and §6 explains why this game cannot produce one without further engineering. + +--- + +## 5. The control — rule 26, honestly + +**The `hooks=off` control does not agree with itself.** Two fresh processes, same guest, same build, +same input save, one End Turn each: + +``` +input ad-turn27-two-raiders.sav 1c8baa27680809d585ab1728391e82729642d32aaedffd5bf95b616f0a11a436 + +OA (Autosave EndTurn).sav 16f63adbf383946db17c381998957172bca803406b7df78f3b03805fef0bbcb8 + (Autosave).sav a634510e7208cceb10d8ce016ceb0153601f11d7291f08122bcdb6418e313331 + +OB (Autosave EndTurn).sav 16f63adbf383946db17c381998957172bca803406b7df78f3b03805fef0bbcb8 + (Autosave).sav 676b1778880b5d4784ba7f6ef48b1a8e56745adab70a815943b7744876686260 + +R1 (probes=8) turn 28 pre 16f63adbf383946db17c381998957172bca803406b7df78f3b03805fef0bbcb8 + turn 28 post 01d6367e051cec539a9266b95b5f41cd1d6434bc8c100c96e8008fc59268da9c + turn 29 pre 5b5618ad1557ae346dc1624ccea38485e3afac967134c7517b17a50dbc88a807 + turn 29 post bf6eec6d4a70a3a6d80baf8df12d6f1cc87ad66d948233adcc7a259d829c4248 +``` + +The **pre**-turn autosave is byte-identical in all three processes and across both configurations — +the load path is deterministic and the instrument does not touch it. The **post**-turn autosave is +different in all three. **So there is no oracle pair for this state and no rung-A calibration pair +came out of this lane** (rule 26: a control that varies exonerates nothing, and one instrumented run +agreeing with one control run would be a `1/k` coincidence, not evidence). + +**But the variation is localised, and it is not where the measurement lives.** The state-checksum +tool (`--floats bits --mask none`) on OA vs OB reports **94 leaf differences**, and on R1 vs OA the +**same 94**, of the same shape: + +| where | leaves | +|---|---| +| `Player[32 "The Eternal Empire"]` — `ShipRecs`, `odes`, `designs`, `Sav`, `Maint`, `PvSav`, `FNGNum` | 41 | +| AI fleets (`Sigma/Tau/Upsilon/Phi/Chi/Psi Fleet VI`, ids and `Pos`/`FtOrig`/`FPlan`) | ~35 | +| AI build queues (`Sys[368]/BQ`, `Sys[272]/BQ`) | 4 | +| `turnstats/history` rows for player 32 | 4 | +| `/Sim/ModCount`, `/Sim/NumFlts`, `/Sim/DesignIDs[]`, `/Sim/FleetIDs[]`, `/Sim/ShipIDs[]`, `/Summary/Checksum` | 6 | + +Every one of them is the AI empire deciding differently — the per-process AI seed rule 26 pinned on +`turn1-state`, at turn 27 with a much larger AI. **Nothing else moves.** The digests that matter, +printed by `state_checksum.py --tree`, are bit-identical in **all three** post-turn saves: + +``` + /Sim/RNG 1e458a997f51bbdf (the serialised strategic generator, 2503 B) + /Sim/trdmgr 89643da6fabb386b (all six trade sectors and all three route records, 180 leaves) +``` + +and there is **no leaf under any trade sector, no `trdmgr` leaf, and no player-0 fleet leaf** in +either diff. + +So the defensible statement, which is weaker than an oracle pair and much stronger than nothing: + +> **Three fresh processes — two un-instrumented, one carrying the full `probes=8` + `draw_sites` + +> boundary-ledger instrument — agree bit-for-bit on the strategic generator's serialised state, on +> the entire trade manager, and on every fleet this measurement is about. They disagree only on the +> AI empire's design and build choices.** + +That is a rule-19 result as well as a rule-26 one: **on this state the instrument is +behaviour-neutral on every leaf outside the AI-decision sub-tree, including the generator itself.** +It does not license calling `ad-turn27-two-raiders.sav` a calibration pair, and I am not proposing +it as one. + +**What would make one.** The variation is a *client AI* decision, and `--turn-commands` replay runs +no AI (`command_replay.h:83`). A Rung-B pair captured from this state with the command stream +recorded should be reproducible even though the Rung-A pair is not — that is a cheap, concrete next +step for whoever owns the standalone, and it is the only way this state becomes calibration data. + +--- + +## 6. The sector-816 probe the coordinator asked for — named, costed, **not run** + +Mid-lane the coordinator redirected: move the raider from sector 6 (`TradeID 832`) to **sector 5 +(`TradeID 816`)**, which *does* source routes, so `B` can reach `0x0088b613`. That is the right +experiment and I did not run it. The reason is geometric and it is worth writing down, because it is +not obvious from the saves and it will otherwise cost the next lane the same hour. + +**Every sector that sources a route is out of range of this empire.** Trade-sector node positions +and my two colonies, from `ad-turn27-two-raiders.sav`; the hull range of every cruiser I can build +is **9.0 ly**, and the fleet panel's `Range: 4.0 (4.0)` on the raiders at sector 6 confirms range is +consumed cumulatively from the last supply point: + +| sector | sources a route at turn 27? | from Epsilon Eridani (idx 0, home) | from Downbelow (idx 12, my only other colony) | +|---|---|---|---| +| 752 | no | 12.85 | 8.43 | +| 768 | **yes** (`trfr 14`, ×2) | 11.53 | **10.14** | +| 784 | no | 9.36 | 3.49 | +| 800 | no | 9.37 | 11.77 | +| **816** | **yes** (`trfr 18`) | **15.66** | **12.12** | +| 832 | no | 4.99 | 4.56 | + +The two in-range sectors (832 at 4.56, 784 at 3.49) source nothing; the two that source routes are +10.14 and 12.12 ly away against a 9.0 ly hull. Confirmed from the UI as well: with Trade View on, +**only sector 6's cube is drawn on the map at any zoom**, so no other sector node is even a +clickable move target from where this empire stands. + +**The workload that would reach it, costed from the Build screen.** The player's stock +**`Extended Range` destroyer** has **`Range 27.0`**, construction cost 2,252, node speed 4.0 +(screenshot `s9`). One of those, built at Epsilon Eridani, reaches sector 816's node (15.66 ly, ~4 +turns at node speed 4.0) or sector 768's (11.53 ly, ~3 turns). Build is ~1–2 turns at this colony's +3,985/turn ship-construction budget. **So the probe is ~6 turns of play from +`ad-turn27-two-raiders.sav`, and it needs nothing that is not already unlocked.** + +Two warnings for whoever runs it, both from arithmetic rather than opinion: + +* A **destroyer** takes the `nDE` branch: `odds = 0.05000000074505806 + 0.009999999776482582 = 0.06`, + doubled to **0.12** if sector 816's AI `Freighters` fleet satisfies `freighterInSector`. That is a + **1-in-8 chance per fleet per turn** of `A` succeeding, and `B` only runs on a success. At 0.12, + four turns with one fleet is a 40% chance of ever seeing `B` — **send several fleets, or expect to + measure a lot of turns.** A cruiser would be 0.21 (0.42 doubled) but cannot get there; a custom + cruiser design carrying the `Extended Range` mission section would fix that, at the cost of driving + the Design screen. +* Sector 816's `tsct` is **2** — bit 1, the *AI's* index, not mine — so `TradeSector_PlayerTradesHere` + is false for player 0 and **no `FtFlg & 0x800` is required**, exactly as on sector 832. `tscr` is + 253 there too. The gate is otherwise identical; only `G_B1b` changes. + +**Corpus count for the sector-816 predicate: still 0 of 22.** Nothing here changes that, and my zero +on `0x0088b613` is a zero *on sector 832*, where `G_B1b` provably fails — it is not a zero on the +predicate AG named. + +--- + +## 7. Coverage and what was not done (rule 15) + +* **Two instrumented turns, one process, two fleets, one sector, one ship per fleet, one hull + class.** The multiplicity claim rests on 1 → 2, not on a curve. A third fleet was built and was + sitting at the home system throughout (`Gamma Fleet`, `LocID 48`); ordering it to sector 6 and + re-measuring would give the 3-point curve cheaply and was not done. +* **The `design+0x12c > 1` short-circuit is still unpriced.** The Dreadnought category is empty in + this game, so no such hull exists to build. It stays a static read. +* **`B`'s inner `NextInt` (`0x0088b613`) and `FUN_00820af0`'s `NextFloat` (`0x00820c1b`) are still + unfired**, here as everywhere. §6 is the recipe. +* **The freighter doubling is untested.** Sector 832 has no freighter, so `param_2` was false on + every roll this lane took, and the `odds + odds` branch was never entered. +* **`bestScale` was 1.0 on every roll** — no ship carried flag `0x100000`, so the 0.33 multiplier is + a static read only. +* **The spy half is untouched**, as instructed. +* **One accidental UI action, disclosed:** during the sector-816 feasibility check I mis-clicked the + savings/research slider on the map panel in a throw-away `hooks=off` session. That session was + discarded and **no save used in §3 or §5 descends from it** — R1, OA and OB all load + `ad-turn27-two-raiders.sav` from disk in a fresh process. +* **No probe wanted `probes=11`.** Nothing in this lane needed an index above 7; the four + uninstalled rows are reported as NOT INSTALLED and never as zeros. + +--- + +## 8. Artifacts + +| what | where | +|---|---| +| input state, two raiders on sector 6, turn 27 | `verify/results/saves/ad-turn27-two-raiders.sav` | +| `probes=8` trace, two instrumented End Turns | `verify/traces/ad-r1-turn28-turn29.jsonl` | +| shim log for R1 (probe/drawsite install status) | `verify/results/shim/ad/ad-r1-shim.log` | +| control autosaves, two fresh `hooks=off` processes | `verify/results/saves/ad-oracle-{A,B}-post.sav` | +| leaf-level diff of the two controls | `verify/results/state-checksum/ad-oracleA-vs-oracleB.txt` | +| instrument | `sots-engine` `src/shim/shim.cfg.hp8`, **unchanged**; build `ad-0c6d0a3-20260909T0159Z` | +| build tree | CT111 `/srv/re-lab/build/sots-engine-ad` (`rm -rf`'d before the build; dist `/srv/re-lab/shim/dist-ad`) | + +**New content for the coverage ratchet (rule 27):** nothing new in kind — the same `CnRad`, +`tscr = 253` and non-star `Flt.LocID` lane AC's saves already carry, now with **two** fleets at one +sector node and `tsnumflt = 2` naming both. + +## 9. VM141 as left + +Guest **restored** and the hold **released**. The game is stopped; `C:\SOTS\shim.cfg` is +`shim.cfg.hoff`; `C:\SOTS\binkw32.dll` is this lane's build; `C:\SOTS\SavedGames` is back to the +13-file set lane AC left (byte-identical, verified by sha256 against +`C:\SOTS\SavedGames-adstash`, which has been removed) **plus** `ad-turn27-two-raiders.sav`, so +**Load-dialog row positions have moved again — screenshot the dialog, do not reuse a remembered +row.** Left in place, all additive and harmless: `C:\SOTS\shimdist-ad`, `C:\SOTS\ui\ad-*.ps1` +(`ad-go.ps1` takes `-Cfg`, `ad-ui.ps1` writes `cmd.txt` and runs the helper once) and this lane's +intermediate saves and traces under `C:\SOTS\ui\ad-*`. `click_helper.ps1` is **unmodified** from lane +AC's version. + +**Two things that cost this lane time, for the next holder:** + +* **Startup is ~4½ minutes on this guest, not 60 seconds**, and the intro is three separate movies. + `qm sendkey 141 esc` skips them but only once the movie has focus; the reliable form is the click + helper's `fg` + `key {ESC}` repeated three times, then wait ~90 s more for the main menu. Loading a + turn-27 save is a further **3–4 minutes**. Budget ~9 minutes per run before the first End Turn, and + screenshot at every step — a QMP `screendump ... -f png` is fresh and cheap. +* **The `End Turn` click after leaving Move mode is swallowed once.** The first click exits the mode; + the turn only starts on the second. Screenshot for the progress bar rather than assuming. + +--- + +## Proposed board rows + +New row: + +``` +| The trade-raid roll is PER FLEET: 2 raiders on one sector = 2 entries, 2 words; B returns without drawing | control-flow | verified | high | 100% | 2026-09-08 | Lane AD, VM141, `findings/control-flow/raid-gate-multiplicity.md`. Two single-cruiser fleets parked on sector 6 (TradeID 832) from ac-turn22-raider.sav: `TradeManager::Slot13RngCalleeA` entered **2x** per End Turn on BOTH measured turns against lane AC's 1, `OnAllCombatDone_Tail` costs **2** words against AC's 1, and the return-address ledger prices the site exactly - 0x00820e18 calls=2 words=2, bracket residual 0. H-sector (one roll per sector) is DEAD; the cost is `sum over qualifying fleets`. `vslot13` is still entered ONCE per turn, so the multiplicity is the caller's loop over StrategyServer+0x64, exactly as AC read it. Instrument `probes=8` (the byte-neutral set - NOT 11), shim `ad-0c6d0a3-20260909T0159Z`, cfg shim.cfg.hp8 unmodified, own build dir /srv/re-lab/build/sots-engine-ad rm -rf'd first. CONSTANTS READ FROM THE IMAGE (rule 23, all WIDENED FLOATS): ODDS_CR 0x009e20d8 = (double)0.2f, ODDS_DE 0x009e5060 = (double)0.05f, PER_SHIP 0x009e31c0 = (double)0.01f, and a per-ship scale 0x009f8d48 = 0.33f that REDUCES the odds when ship+0x18 & 0x100000. One-cruiser fleet odds = 0.21000000275671482; six rolls across AC+AD gave two successes (expectation 1.26) - consistent, not validated. `Slot13RngCalleeB` entered 1x on turn 28 and cost **0 words** by return-address attribution - and lane AG's reading that RNG_NextInt has NO zero-bound early-out turns that into a PROOF that B returned before its target pick, i.e. the candidate list was empty (G_B4), reproduced with a fleet AC never had. trdmgr holds 3 routes, trfr 18/14/14, sourced in sectors 816 and 768 - NONE in 832 | +``` + +``` +| NO ORACLE PAIR for the turn-27 raider state - the control varies, but ONLY in the AI's decisions, and /Sim/RNG is bit-identical across three processes | meta | verified | high | 100% | 2026-09-08 | Lane AD (rule 26). Two `hooks=off` runs of one End Turn from ad-turn27-two-raiders.sav in two fresh processes gave DIFFERENT post-turn autosaves (a634510e / 676b1778); the pre-turn autosave is byte-identical in all three processes (16f63adb), so the load path is deterministic and the divergence is inside the turn. So NO rung-A calibration pair came out of this state and none is proposed. BUT the state-checksum localises the variation completely: 94 leaves, ALL of them Player[32 "The Eternal Empire"] designs/ShipRecs/odes/build queues/fleet ids and positions, plus ModCount, NumFlts, the three id lists and Summary.Checksum. `/Sim/RNG` = 1e458a997f51bbdf and `/Sim/trdmgr` = 89643da6fabb386b in ALL THREE post-turn saves (two hooks=off and one probes=8), and NO trade-sector, trdmgr or player-0 fleet leaf appears in either diff. Two consequences: (a) every number lane AD reports is read off a sub-tree the control reproduces bit-for-bit; (b) RULE 19, on this state: the probes=8 + draw_sites + boundary-ledger instrument is behaviour-neutral on every leaf OUTSIDE the AI-decision sub-tree, including the serialised strategic generator. The named next step is a RUNG B pair - `--turn-commands` replay runs no AI, so a captured command stream should make this state reproducible where Rung A cannot | +``` + +``` +| Sector 816 is UNREACHABLE from lane AC's empire - the AG probe needs a 27 ly hull, and one is already buildable | control-flow | verified | high | 100% | 2026-09-08 | Lane AD, measured from ad-turn27-two-raiders.sav geometry + the Build screen. Node distances from the human's only two colonies (Epsilon Eridani idx 0, Downbelow idx 12) against a 9.0 ly cruiser range: sector 816 = 15.66 / 12.12, sector 768 = 11.53 / 10.14, sector 752 = 12.85 / 8.43, sector 800 = 9.37 / 11.77, sector 784 = 9.36 / 3.49, sector 832 = 4.99 / 4.56. The only two sectors IN range (832, 784) source no route; the only two that source routes (816 via trfr 18, 768 via trfr 14 x2) are out of range. With Trade View on, only sector 6's cube renders at any zoom, so no other sector node is even a clickable move target. THE FIX IS ALREADY UNLOCKED: the stock `Extended Range` DESTROYER has Range 27.0, construction cost 2,252, node speed 4.0 - ~1-2 turns to build, ~4 turns to sector 816's node, so AG's probe is ~6 turns of play and needs no research. TWO WARNINGS: a destroyer takes the nDE odds branch, 0.05f + 0.01f = 0.06 (0.12 if the AI Freighters fleet in 816 satisfies the doubling), i.e. a 1-in-8 success per fleet per turn - send several fleets or measure many turns; and sector 816's tsct = 2 is the AI's bit, not player 0's, so no FtFlg & 0x800 is required there, exactly as on 832 | +``` + +Edits to existing rows: + +- **Row 62** (guest holders) — `VM141 = FREE (lane AD released 2026-09-08; guest restored, SavedGames back to AC's 13-file set byte-identical PLUS ad-turn27-two-raiders.sav, so Load-dialog rows have moved AGAIN - screenshot the dialog. Lane AD left C:\SOTS\shimdist-ad + C:\SOTS\ui\ad-*.ps1; click_helper.ps1 unmodified. GOTCHA: startup on this guest is ~4.5 min through THREE intro movies (fg + key {ESC} x3 via the click helper, then ~90 s), and loading a turn-27 save is a further 3-4 min - budget ~9 min per run before the first End Turn. GOTCHA: the first End Turn click after leaving Move mode is swallowed exiting the mode; the turn starts on the second click.)` +- **Row 207** — append: `PRICED 2026-09-08 (lane AD): 0x00820e18 costs ONE WORD PER QUALIFYING FLEET, not one per sector - two raiders on one sector give calls=2 words=2. 0x0088b613 (B's NextInt) still UNFIRED and now known to be a proof-carrying zero: RNG_NextInt has no zero-bound early-out (lane AG), so B costing 0 words means B never reached the pick.` +- **Row 399** — append: `Lane AD reproduced AC's B-at-zero-words with a SECOND, independent fleet and read the failed conjunct out of the save: trdmgr's three routes have trfr 18/14/14, sourced in sectors 816 and 768, none in 832 - G_B1b, exactly as lane AG decoded. AD's data does NOT distinguish AG's per-system vs sector-indexed reading of TradeManager+0x0c: on sector 832 both predict the same zero.` +- **Row 186** (`RNG LEDGER CLOSED`) — append to the existing qualification: `Lane AD 2026-09-08: the tail site's cost is not a constant at all - it is one word per permitted raider parked on a sector node, measured at 2 with two fleets. Any per-turn tail figure is a statement about the fleet count in that state.` diff --git a/verify/results/saves/ad-oracle-A-post.sav b/verify/results/saves/ad-oracle-A-post.sav new file mode 100644 index 0000000..9734855 Binary files /dev/null and b/verify/results/saves/ad-oracle-A-post.sav differ diff --git a/verify/results/saves/ad-oracle-B-post.sav b/verify/results/saves/ad-oracle-B-post.sav new file mode 100644 index 0000000..7135359 Binary files /dev/null and b/verify/results/saves/ad-oracle-B-post.sav differ diff --git a/verify/results/saves/ad-turn27-two-raiders.sav b/verify/results/saves/ad-turn27-two-raiders.sav new file mode 100644 index 0000000..4743f31 Binary files /dev/null and b/verify/results/saves/ad-turn27-two-raiders.sav differ diff --git a/verify/results/shim/ad/ad-r1-shim.log b/verify/results/shim/ad/ad-r1-shim.log new file mode 100644 index 0000000..49aa6a3 --- /dev/null +++ b/verify/results/shim/ad/ad-r1-shim.log @@ -0,0 +1,119 @@ +22:19:04.382 [tid 9080] ==== sots-engine shim (binkw32 proxy) build ad-0c6d0a3-20260909T0159Z ==== +22:19:04.382 [tid 9080] exe: C:\SOTS\Sword of the Stars.exe +22:19:04.382 [tid 9080] exe base=0x00210000 (link-time image base 0x00400000, ASLR delta -2031616) pid=3752 shim=72a60000 +22:19:04.382 [tid 9080] addresses: Source: sots-re ghidra/addresses.json @ bdaa26f, generated 2026-09-08 by tools/gen_addresses.py +22:19:04.397 [tid 9080] config: hooks=trace +22:19:04.397 [tid 9080] config: hook.Shim::SelfTest::Fill=off +22:19:04.397 [tid 9080] config: hook.Mars::GlobalConsts::LoadFile=off +22:19:04.397 [tid 9080] config: hook.Game::WeaponDictionary::Init=off +22:19:04.397 [tid 9080] config: hook.Game::SectionDictionary::SectionDictionary=off +22:19:04.397 [tid 9080] config: hook.Game::ServerPlayer::ComputeBudget=off +22:19:04.397 [tid 9080] config: hook.Game::TechTree::ProcessResearch=off +22:19:04.397 [tid 9080] config: hook.Game::ServerPlayer::OnTechResearched=off +22:19:04.397 [tid 9080] config: hook.Game::ServerSystem::ProcessTurn=off +22:19:04.397 [tid 9080] config: hook.Game::ServerPlayer::ProcessTurn=off +22:19:04.397 [tid 9080] config: hook.Game::ServerSystem::GroupOutput=off +22:19:04.397 [tid 9080] config: hook.Game::ServerSystem::ComputeTotalOutput=off +22:19:04.397 [tid 9080] config: hook.Game::StrategyServer::MoveFleet=off +22:19:04.397 [tid 9080] config: hook.Game::StrategyServer::ProcessFleetMovement=off +22:19:04.397 [tid 9080] config: hook.Game::StrategyHost::Autosave=trace +22:19:04.397 [tid 9080] config: hook.Game::StrategyServer::ProcessTurn=trace +22:19:04.397 [tid 9080] config: hook.Game::StrategyServer::OnAllCombatDone_Tail=trace +22:19:04.397 [tid 9080] config: hook.Game::StrategyServer::ApplyEncounterResult=trace +22:19:04.397 [tid 9080] config: hook.Game::StrategyServer::NodeLineDecay=trace +22:19:04.397 [tid 9080] config: hook.Game::StrategyServer::ProcessNodeSpaceTravel=trace +22:19:04.397 [tid 9080] config: hook.Game::EncounterDetect::AssignContacts=trace +22:19:04.397 [tid 9080] config: hook.Game::EncounterDetect::ProcessTeamRecord=trace +22:19:04.397 [tid 9080] config: fpu.sample_turn=off +22:19:04.397 [tid 9080] config: fpu.sample_ticks=off +22:19:04.397 [tid 9080] config: trace.inline_max=64 +22:19:04.397 [tid 9080] config: trace.path=C:\SOTS\shim.trace.jsonl +22:19:04.397 [tid 9080] config: trace.flush=always +22:19:04.397 [tid 9080] config: probes=8 -> 8 lane-H entry probes +22:19:04.460 [tid 9080] trace: C:\SOTS\shim.trace.jsonl (default mode trace, inline_max 64, flush always) +22:19:04.460 [tid 9080] hook: Mars_Application_Initialize rva=0x004a0e50 -> va=006b0e50 +22:19:04.460 [tid 9080] hook: MH_Initialize -> MH_OK +22:19:04.460 [tid 9080] hook: MH_CreateHook -> MH_OK (trampoline=009d0fe0) +22:19:04.476 [tid 9080] hook: MH_EnableHook -> MH_OK +22:19:04.476 [tid 9080] cfg: GlobalConsts hook ready (scale constant 0.017453292519943295) +22:19:04.476 [tid 9080] hook: Mars::GlobalConsts::LoadFile rva=0x004b73c0 mode=off (not installed) +22:19:04.476 [tid 9080] dict: dictionaries hook ready (crt new=74b3232b delete=74b30174) +22:19:04.476 [tid 9080] hook: Game::WeaponDictionary::Init rva=0x0019a4c0 mode=off (not installed) +22:19:04.476 [tid 9080] hook: Game::SectionDictionary::SectionDictionary rva=0x00176f40 mode=off (not installed) +22:19:04.476 [tid 9080] research: ProcessResearch hook ready (Cost=0038da00, node=0x34, rng=0x9cc, fpu_cw=0x027f) +22:19:04.476 [tid 9080] hook: Game::TechTree::ProcessResearch rva=0x001876c0 mode=off (not installed) +22:19:04.476 [tid 9080] techfx: OnTechResearched hook ready (regions=15, gate=0/0, fpu_cw=0x027f) +22:19:04.476 [tid 9080] hook: Game::ServerPlayer::OnTechResearched rva=0x00491790 mode=off (not installed) +22:19:04.476 [tid 9080] hook: Game::ServerPlayer::ComputeBudget rva=0x00463030 mode=off (not installed) +22:19:04.476 [tid 9080] hook: Game::ServerSystem::ProcessTurn rva=0x003598e0 mode=off (not installed) +22:19:04.476 [tid 9080] hook: Game::ServerSystem::GroupOutput rva=0x0034b7a0 mode=off (not installed) +22:19:04.476 [tid 9080] hook: Game::ServerSystem::ComputeTotalOutput rva=0x00350480 mode=off (not installed) +22:19:04.476 [tid 9080] player_turn: ServerPlayer::ProcessTurn hook armed (ratio helper at 0038e950) +22:19:04.476 [tid 9080] hook: Game::ServerPlayer::ProcessTurn rva=0x00491340 mode=off (not installed) +22:19:04.476 [tid 9080] hook: Game::StrategyServer::MoveFleet rva=0x003d9ee0 mode=off (not installed) +22:19:04.476 [tid 9080] hook: Game::StrategyServer::ProcessFleetMovement rva=0x003da9a0 mode=off (not installed) +22:19:04.476 [tid 9080] hook: Game::StrategyHost::Autosave rva=0x00495210 -> va=006a5210 MH_CreateHook -> MH_OK (trampoline=009d0fc0) +22:19:04.491 [tid 9080] hook: Game::StrategyHost::Autosave MH_EnableHook -> MH_OK mode=trace +22:19:04.491 [tid 9080] hook: Game::StrategyServer::ProcessTurn rva=0x003dc6c0 -> va=005ec6c0 MH_CreateHook -> MH_OK (trampoline=009d0fa0) +22:19:04.507 [tid 9080] hook: Game::StrategyServer::ProcessTurn MH_EnableHook -> MH_OK mode=trace +22:19:04.507 [tid 9080] hook: Game::StrategyServer::OnAllCombatDone_Tail rva=0x003d92a0 -> va=005e92a0 MH_CreateHook -> MH_OK (trampoline=009d0f80) +22:19:04.522 [tid 9080] hook: Game::StrategyServer::OnAllCombatDone_Tail MH_EnableHook -> MH_OK mode=trace +22:19:04.522 [tid 9080] hook: Game::StrategyServer::ApplyEncounterResult rva=0x003d8920 -> va=005e8920 MH_CreateHook -> MH_OK (trampoline=009d0f60) +22:19:04.538 [tid 9080] hook: Game::StrategyServer::ApplyEncounterResult MH_EnableHook -> MH_OK mode=trace +22:19:04.538 [tid 9080] hook: Game::StrategyServer::NodeLineDecay rva=0x003ae010 -> va=005be010 MH_CreateHook -> MH_OK (trampoline=009d0f40) +22:19:04.554 [tid 9080] hook: Game::StrategyServer::NodeLineDecay MH_EnableHook -> MH_OK mode=trace +22:19:04.554 [tid 9080] hook: Game::StrategyServer::ProcessNodeSpaceTravel rva=0x003a0e20 -> va=005b0e20 MH_CreateHook -> MH_OK (trampoline=009d0f20) +22:19:04.569 [tid 9080] hook: Game::StrategyServer::ProcessNodeSpaceTravel MH_EnableHook -> MH_OK mode=trace +22:19:04.569 [tid 9080] hook: Game::EncounterDetect::AssignContacts rva=0x003aa240 -> va=005ba240 MH_CreateHook -> MH_OK (trampoline=009d0f00) +22:19:04.585 [tid 9080] hook: Game::EncounterDetect::AssignContacts MH_EnableHook -> MH_OK mode=trace +22:19:04.585 [tid 9080] hook: Game::EncounterDetect::ProcessTeamRecord rva=0x003ca640 -> va=005da640 MH_CreateHook -> MH_OK (trampoline=009d0ee0) +22:19:04.601 [tid 9080] hook: Game::EncounterDetect::ProcessTeamRecord MH_EnableHook -> MH_OK mode=trace +22:19:04.601 [tid 9080] hook: Game::StrategyServer::BeginProcessTurn rva=0x003d98e0 -> va=005e98e0 MH_CreateHook -> MH_OK (trampoline=009d0ec0) +22:19:04.616 [tid 9080] hook: Game::StrategyServer::BeginProcessTurn MH_EnableHook -> MH_OK mode=trace +22:19:04.616 [tid 9080] hook: Game::SVSOSwarmQueen::OnTurnBegin rva=0x00129930 -> va=00339930 MH_CreateHook -> MH_OK (trampoline=009d0ea0) +22:19:04.632 [tid 9080] hook: Game::SVSOSwarmQueen::OnTurnBegin MH_EnableHook -> MH_OK mode=trace +22:19:04.632 [tid 9080] hook: Game::SVSOSwarmQueen::RegisterHives rva=0x00127630 -> va=00337630 MH_CreateHook -> MH_OK (trampoline=009d0e80) +22:19:04.647 [tid 9080] hook: Game::SVSOSwarmQueen::RegisterHives MH_EnableHook -> MH_OK mode=trace +22:19:04.647 [tid 9080] hook: Game::SVSOSwarmQueen::TickHives rva=0x00127770 -> va=00337770 MH_CreateHook -> MH_OK (trampoline=009d0e60) +22:19:04.663 [tid 9080] hook: Game::SVSOSwarmQueen::TickHives MH_EnableHook -> MH_OK mode=trace +22:19:04.663 [tid 9080] hook: Game::SVSOSlaversRefuel::UpdateDifficultyTier rva=0x00115820 -> va=00325820 MH_CreateHook -> MH_OK (trampoline=009d0e40) +22:19:04.679 [tid 9080] hook: Game::SVSOSlaversRefuel::UpdateDifficultyTier MH_EnableHook -> MH_OK mode=trace +22:19:04.679 [tid 9080] hook: Mars::RNG::Seed rva=0x0009fdf0 -> va=002afdf0 MH_CreateHook -> MH_OK (trampoline=009d0e20) +22:19:04.694 [tid 9080] hook: Mars::RNG::Seed MH_EnableHook -> MH_OK mode=trace +22:19:04.694 [tid 9080] hook: Game::StrategyApp::RunAI rva=0x004706f0 -> va=006806f0 MH_CreateHook -> MH_OK (trampoline=009d0e00) +22:19:04.710 [tid 9080] hook: Game::StrategyApp::RunAI MH_EnableHook -> MH_OK mode=trace +22:19:04.726 [tid 9080] drawsite: Mars::RNG::NextFloat rva=0x0007d830 -> va=0028d830 create=MH_OK enable=MH_OK +22:19:04.741 [tid 9080] drawsite: Mars::RNG::NextInt rva=0x000271c0 -> va=002371c0 create=MH_OK enable=MH_OK +22:19:04.757 [tid 9080] drawsite: Mars::RNG::Chance rva=0x004e6dd0 -> va=006f6dd0 create=MH_OK enable=MH_OK +22:19:04.772 [tid 9080] drawsite: Mars::RNG::NextUInt rva=0x000f7670 -> va=00307670 create=MH_OK enable=MH_OK +22:19:04.788 [tid 9080] drawsite: Mars::RNG::FloatRange rva=0x0007d8a0 -> va=0028d8a0 create=MH_OK enable=MH_OK +22:19:04.804 [tid 9080] drawsite: Mars::RNG::IntRangeBell rva=0x004e6d80 -> va=006f6d80 create=MH_OK enable=MH_OK +22:19:04.819 [tid 9080] drawsite: Mars::RNG::GaussianRange rva=0x004e6e30 -> va=006f6e30 create=MH_OK enable=MH_OK +22:19:04.819 [tid 9080] probe: installing 8 of 12 (probes= in shim.cfg) +22:19:04.835 [tid 9080] probe: Game::ServerSpyManager::vslot13 rva=0x004877b0 -> va=006977b0 create=MH_OK enable=MH_OK +22:19:04.851 [tid 9080] probe: Game::ServerSpyManager::vslot14 rva=0x0048db80 -> va=0069db80 create=MH_OK enable=MH_OK +22:19:04.866 [tid 9080] probe: Game::ServerTradeManagerImpl::vslot13 rva=0x0048ef80 -> va=0069ef80 create=MH_OK enable=MH_OK +22:19:04.882 [tid 9080] probe: Game::ServerTradeManagerImpl::vslot15 rva=0x0042cca0 -> va=0063cca0 create=MH_OK enable=MH_OK +22:19:04.897 [tid 9080] probe: Game::SpyManager::Slot13RngCallee rva=0x004408e0 -> va=006508e0 create=MH_OK enable=MH_OK +22:19:04.913 [tid 9080] probe: Game::TradeManager::Slot13RngCalleeA rva=0x00420ca0 -> va=00630ca0 create=MH_OK enable=MH_OK +22:19:04.929 [tid 9080] probe: Game::TradeManager::Slot13RngCalleeB rva=0x0048b440 -> va=0069b440 create=MH_OK enable=MH_OK +22:19:04.944 [tid 9080] probe: Game::ServerTradeManager::CreateRaidEncounter rva=0x004938a0 -> va=006a38a0 create=MH_OK enable=MH_OK +22:19:04.944 [tid 9080] watch: disabled (watch=off) +22:19:04.944 [tid 9080] aiorders: disabled (aiorders=off) +22:19:04.944 [tid 9080] fpu: module init, entry cw=0x027f 53bit-double/nearest; force=off value=0x0000 sample_ticks=off +22:19:04.944 [tid 9080] fpu: sample_turn=off (off releases StrategyServer::ProcessTurn for another hook) +22:19:04.944 [tid 9080] fpu: StrategyClient::EndTurn rva=0x00383be0 -> va=00593be0 MH_CreateHook -> MH_OK (trampoline=009d0c00) +22:19:04.960 [tid 9080] fpu: StrategyClient::EndTurn MH_EnableHook -> MH_OK +22:19:04.960 [tid 9080] fpu: StrategyServer::BeginProcessTurn rva=0x003d98e0 -> va=005e98e0 MH_CreateHook -> MH_ERROR_ALREADY_CREATED (trampoline=00000000) +22:19:04.960 [tid 9080] fpu: StrategyServer::ProcessTurn rva=0x003dc6c0 not installed (sampler off) +22:19:04.960 [tid 9080] fpu: DemoApp::OnTick rva=0x0049a640 not installed (sampler off) +22:19:04.960 [tid 9080] selftest: Shim::SelfTest::Fill mode=off checksum=075ef0c3 records=0 +22:19:04.976 [tid 9080] Application::Initialize called (this=02e88128) +22:23:40.689 [tid 9080] fpu: sample at StrategyClient::EndTurn (this=0de28f48): cw=0x127f 53bit-double/nearest [no fpu.force configured] +22:23:43.814 [tid 9080] fpu: sample at StrategyClient::EndTurn (this=326fba80): cw=0x127f 53bit-double/nearest [no fpu.force configured] +22:23:43.845 [tid 9080] fpu: sample at StrategyClient::EndTurn (this=326fe630): cw=0x127f 53bit-double/nearest [no fpu.force configured] +22:23:43.892 [tid 9080] fpu: sample at StrategyClient::EndTurn (this=326fc910): cw=0x127f 53bit-double/nearest [no fpu.force configured] +22:25:25.392 [tid 9080] fpu: sample at StrategyClient::EndTurn (this=0de28f48): cw=0x127f 53bit-double/nearest [no fpu.force configured] +22:25:28.548 [tid 9080] fpu: sample at StrategyClient::EndTurn (this=326fba80): cw=0x127f 53bit-double/nearest [no fpu.force configured] +22:25:28.548 [tid 9080] fpu: sample at StrategyClient::EndTurn (this=326fe630): cw=0x127f 53bit-double/nearest [no fpu.force configured] +22:25:28.595 [tid 9080] fpu: sample at StrategyClient::EndTurn (this=326fc910): cw=0x127f 53bit-double/nearest [no fpu.force configured] diff --git a/verify/results/state-checksum/ad-oracleA-vs-oracleB.txt b/verify/results/state-checksum/ad-oracleA-vs-oracleB.txt new file mode 100644 index 0000000..5718641 --- /dev/null +++ b/verify/results/state-checksum/ad-oracleA-vs-oracleB.txt @@ -0,0 +1,98 @@ +A 1faf04cad2bbf2d7e5ecf560b8807504 /tmp/claude-1000/-home-alex/ec8e34f8-af37-4ef2-a309-ed6a15293097/scratchpad/ad-oA-post.sav +B 53043168ad03cae13355db9f5f381b50 /tmp/claude-1000/-home-alex/ec8e34f8-af37-4ef2-a309-ed6a15293097/scratchpad/ad-oB-post.sav +policy: floats=bits mask=none reader=74fd562c75e2679e +DIVERGED: 94 leaf difference(s) + /Summary/Checksum: -1043321805 -> 1995746704 + /Sim/DesignIDs[]: removed [2002], added [2018] (85 -> 85 entries) + /Sim/FleetIDs[]: removed [], added [2002] (58 -> 59 entries) + /Sim/ShipIDs[]: list-reordered + /Sim/ModCount: 1496 -> 1500 + /Sim/turnstats/history/hist[1]/stats[27]/inc: 839755 -> 851157 + /Sim/turnstats/history/hist[1]/stats[27]/sav: 11167335 -> 11248465 + /Sim/turnstats/history/hist[1]/stats[27]/shpt[0]: 177 -> 178 + /Sim/turnstats/history/hist[1]/stats[27]/shpt[1]: 31 -> 30 + /Sim/players/Player[32 "The Eternal Empire"]/Sav: 11167335 -> 11248465 + /Sim/players/Player[32 "The Eternal Empire"]/Maint: 181500 -> 179000 + /Sim/players/Player[32 "The Eternal Empire"]/FNG/FNGNum: 144 -> 145 + /Sim/players/Player[32 "The Eternal Empire"]/PvSav: 10327580 -> 10397308 + /Sim/players/Player[32 "The Eternal Empire"]/ShipRecs/srd[34]: only-in-B + /Sim/players/Player[32 "The Eternal Empire"]/ShipRecs/src[34]: only-in-B + /Sim/players/Player[32 "The Eternal Empire"]/ShipRecs/srb[37]: only-in-B + /Sim/players/Player[32 "The Eternal Empire"]/ShipRecs/srl[37]: only-in-B + /Sim/players/Player[32 "The Eternal Empire"]/ShipRecs/sri[37]: only-in-B + /Sim/players/Player[32 "The Eternal Empire"]/ShipRecs/srb[0]: 268 -> 269 + /Sim/players/Player[32 "The Eternal Empire"]/ShipRecs/sri[0]: 177 -> 178 + /Sim/players/Player[32 "The Eternal Empire"]/ShipRecs/srb[1]: 31 -> 30 + /Sim/players/Player[32 "The Eternal Empire"]/ShipRecs/sri[1]: 31 -> 30 + /Sim/players/Player[32 "The Eternal Empire"]/ShipRecs/srbd: 34 -> 35 + /Sim/players/Player[32 "The Eternal Empire"]/ShipRecs/srb[24]: 24 -> 27 + /Sim/players/Player[32 "The Eternal Empire"]/ShipRecs/sri[24]: 16 -> 19 + /Sim/players/Player[32 "The Eternal Empire"]/ShipRecs/srb[25]: 33 -> 31 + /Sim/players/Player[32 "The Eternal Empire"]/ShipRecs/sri[25]: 18 -> 16 + /Sim/players/Player[32 "The Eternal Empire"]/ShipRecs/srb[30]: 5 -> 4 + /Sim/players/Player[32 "The Eternal Empire"]/ShipRecs/sri[30]: 5 -> 4 + /Sim/players/Player[32 "The Eternal Empire"]/ShipRecs/srb[31]: 11 -> 10 + /Sim/players/Player[32 "The Eternal Empire"]/ShipRecs/sri[31]: 11 -> 10 + /Sim/players/Player[32 "The Eternal Empire"]/ShipRecs/srd[33]: 1826 -> 2018 + /Sim/players/Player[32 "The Eternal Empire"]/ShipRecs/srb[36]: 4 -> 1 + /Sim/players/Player[32 "The Eternal Empire"]/ShipRecs/sri[36]: 4 -> 1 + /Sim/players/Player[32 "The Eternal Empire"]/designs/Des[2002 "Bravestar Mk 3"]: only-in-A + /Sim/players/Player[32 "The Eternal Empire"]/designs/Des[2018 "Bravestar Mk 3"]: only-in-B + /Sim/players/Player[32 "The Eternal Empire"]/odes/.[2]/odid: 770 -> 1106 + /Sim/players/Player[32 "The Eternal Empire"]/odes/.[3]/odid: 1106 -> 1042 + /Sim/players/Player[32 "The Eternal Empire"]/odes/.[4]/otnF: 28 -> 27 + /Sim/players/Player[32 "The Eternal Empire"]/odes/.[4]/odid: 1042 -> 226 + /Sim/players/Player[32 "The Eternal Empire"]/odes/.[5]/otnF: 27 -> 28 + /Sim/players/Player[32 "The Eternal Empire"]/odes/.[5]/odid: 226 -> 818 + /Sim/players/Player[32 "The Eternal Empire"]/odes/.[6]/odid: 818 -> 978 + /Sim/players/Player[32 "The Eternal Empire"]/odes/.[15]/odid: 1250 -> 1474 + /Sim/players/Player[32 "The Eternal Empire"]/odes/.[16]/odid: 978 -> 1250 + /Sim/players/Player[32 "The Eternal Empire"]/odes/.[17]/otnF: 27 -> 28 + /Sim/players/Player[32 "The Eternal Empire"]/odes/.[17]/odid: 962 -> 2018 + /Sim/players/Player[32 "The Eternal Empire"]/odes/.[18]/otnF: 28 -> 27 + /Sim/players/Player[32 "The Eternal Empire"]/odes/.[18]/odid: 1474 -> 962 + /Sim/systems/Sys[272 "Ko'Graapa"]/BQ/ords/.[desID=978]: only-in-A + /Sim/systems/Sys[272 "Ko'Graapa"]/BQ/ords/.[desID=962]: only-in-B + /Sim/systems/Sys[368 "Kao'Vaanu"]/Pop2/PopG/PopC: 699999970 -> 699999940 + /Sim/systems/Sys[368 "Kao'Vaanu"]/BQ/ords/.[desID=1474]/conleft: 4677 -> 6119 + /Sim/systems/Sys[368 "Kao'Vaanu"]/BQ/ords/.[desID=1474]/ordID: 304 -> 305 + /Sim/systems/Sys[384 "Ka'Trulmo"]/Flt[1]: 1970 -> 1986 + /Sim/NumFlts: 58 -> 59 + /Sim/fleets/Flt[7120 "Upsilon Fleet VI"]: only-in-A + /Sim/fleets/Flt[7152 "Phi Fleet VI"]: only-in-A + /Sim/fleets/Flt[7216 "Chi Fleet VI"]: only-in-A + /Sim/fleets/Flt[2002 "Upsilon Fleet VI"]: only-in-B + /Sim/fleets/Flt[7120 "Phi Fleet VI"]: only-in-B + /Sim/fleets/Flt[7152 "Chi Fleet VI"]: only-in-B + /Sim/fleets/Flt[7216 "Psi Fleet VI"]: only-in-B + /Sim/fleets/Flt[1154 "Eta Fleet IV"]/NShips: 3 -> 2 + /Sim/fleets/Flt[1154 "Eta Fleet IV"]/ships/Ship[5264]: only-in-A + /Sim/fleets/Flt[1970 "Sigma Fleet VI"]/FPlan: only-in-B + /Sim/fleets/Flt[1970 "Sigma Fleet VI"]/Pos/.[0]: 1.013401746749878 -> 1.554553508758545 [4.53951e+06 ulp] + /Sim/fleets/Flt[1970 "Sigma Fleet VI"]/Pos/.[1]: 2.5877604484558105 -> -0.33745646476745605 [2.12772e+09 ulp] + /Sim/fleets/Flt[1970 "Sigma Fleet VI"]/Pos/.[2]: 1.1378376483917236 -> -0.12602603435516357 [2.10677e+09 ulp] + /Sim/fleets/Flt[1970 "Sigma Fleet VI"]/LocID: 384 -> 0 + /Sim/fleets/Flt[1970 "Sigma Fleet VI"]/HFPlan: False -> True + /Sim/fleets/Flt[1970 "Sigma Fleet VI"]/FtTrans: 0 -> 1 + /Sim/fleets/Flt[1970 "Sigma Fleet VI"]/FtOrig/.[0]: 0 -> 1.8894044160842896 (kind int -> float) + /Sim/fleets/Flt[1970 "Sigma Fleet VI"]/FtOrig/.[1]: 0 -> -2.147505760192871 (kind int -> float) + /Sim/fleets/Flt[1970 "Sigma Fleet VI"]/FtOrig/.[2]: 0 -> -0.9080725908279419 (kind int -> float) + /Sim/fleets/Flt[1970 "Sigma Fleet VI"]/FtFlg: 12 -> 13 + /Sim/fleets/Flt[1970 "Sigma Fleet VI"]/PrvPos/.[0]: 1.013401746749878 -> 1.8894044160842896 [7.34844e+06 ulp] + /Sim/fleets/Flt[1970 "Sigma Fleet VI"]/PrvPos/.[1]: 2.5877604484558105 -> -2.147505760192871 [2.15057e+09 ulp] + /Sim/fleets/Flt[1970 "Sigma Fleet VI"]/PrvPos/.[2]: 1.1378376483917236 -> -0.9080725908279419 [2.13032e+09 ulp] + /Sim/fleets/Flt[1970 "Sigma Fleet VI"]/ships/Ship[6976]: only-in-A + /Sim/fleets/Flt[1970 "Sigma Fleet VI"]/ships/Ship[5264]: only-in-B + /Sim/fleets/Flt[1986 "Tau Fleet VI"]/FPlan: only-in-A + /Sim/fleets/Flt[1986 "Tau Fleet VI"]/Pos/.[0]: -0.600679874420166 -> 1.013401746749878 [2.12412e+09 ulp] + /Sim/fleets/Flt[1986 "Tau Fleet VI"]/Pos/.[1]: 2.8708744049072266 -> 2.5877604484558105 [1.18747e+06 ulp] + /Sim/fleets/Flt[1986 "Tau Fleet VI"]/Pos/.[2]: 2.2843918800354004 -> 1.1378376483917236 [8.42517e+06 ulp] + /Sim/fleets/Flt[1986 "Tau Fleet VI"]/LocID: 0 -> 384 + /Sim/fleets/Flt[1986 "Tau Fleet VI"]/HFPlan: True -> False + /Sim/fleets/Flt[1986 "Tau Fleet VI"]/FtTrans: 1 -> 0 + /Sim/fleets/Flt[1986 "Tau Fleet VI"]/FtOrig/.[0]: 1.013401746749878 -> 0 (kind float -> int) + /Sim/fleets/Flt[1986 "Tau Fleet VI"]/FtOrig/.[1]: 2.5877604484558105 -> 0 (kind float -> int) + /Sim/fleets/Flt[1986 "Tau Fleet VI"]/FtOrig/.[2]: 1.1378376483917236 -> 0 (kind float -> int) + /Sim/fleets/Flt[1986 "Tau Fleet VI"]/FtFlg: 13 -> 12 + /Sim/fleets/Flt[1986 "Tau Fleet VI"]/ships/Ship[6992]: only-in-A + /Sim/fleets/Flt[1986 "Tau Fleet VI"]/ships/Ship[6976]: only-in-B diff --git a/verify/traces/ad-r1-turn28-turn29.jsonl b/verify/traces/ad-r1-turn28-turn29.jsonl new file mode 100644 index 0000000..dc06a48 --- /dev/null +++ b/verify/traces/ad-r1-turn28-turn29.jsonl @@ -0,0 +1,35 @@ +{"meta":{"format":1,"build":"ad-0c6d0a3-20260909T0159Z","exe_sha256":"970b7de729956a53094c7eb98aba4270aee98e2fed5daf0d39e290013c90c841","started":"2026-09-09T02:19:04Z","inline_max":64,"hooks":{"Shim::SelfTest::Fill":{"ftol":0,"ftol_kind":"abs","ptr":"ignore","coverage":{"state":"complete","why":"Fill writes buf[0..n) and nothing else; the whole range is a declared region","unmodelled":[]}},"Mars::GlobalConsts::LoadFile":{"ftol":0,"ftol_kind":"abs","ptr":"ignore","coverage":{"state":"partial","why":"","unmodelled":[{"what":"erases each consumed key from the caller's std::map","risk":"medium","why":"the map is a LoadAll temporary; declaring a red-black tree as a region is not possible before the call. First-occurrence-wins is reproduced in game::config::apply instead, so the *effect* is modelled, the container is not","mitigation":"LoadAll's post-state would have to be hooked to see it"},{"what":"writes three kinds of line to the game log (unrecognised key, applied key, expected-but-not-found)","risk":"low","why":"log text is not part of the simulation state","mitigation":""},{"what":"opens the file through the VFS and allocates/releases a refcounted buffer","risk":"low","why":"ours performs the same two calls, so allocation behaviour matches by construction rather than by comparison","mitigation":""},{"what":"String slots assign through the engine's own std::string, leaking one heap block per long string in compare mode","risk":"low","why":"start-up only; documented in docs/M1.md","mitigation":""}]}},"Game::ServerPlayer::ComputeBudget":{"ftol":0,"ftol_kind":"abs","ptr":"ignore","coverage":{"state":"partial","why":"","unmodelled":[{"what":"slots 1, 2, 3, 4, 7 and 11 are produced by callees this milestone does not model (per-system output, trade, ship-carried population, a second manager, the build-queue spend)","risk":"high","why":"they are copied out of the original's own output and back into the same slots, so they match BY CONSTRUCTION and prove nothing","mitigation":"declared input boundary; see budget_inputs.h"},{"what":"ServerSystem::ComputeOutput repairs damaged ships in orbit","risk":"high","why":"replace mode runs the original a second time on a scratch Budget to harvest the six unmodelled slots, so that repair happens TWICE per turn in replace mode and nothing in the trace would show it","mitigation":"guard:budget_object does not reach the ships; unverified"},{"what":"the difficulty-mods row still DRIVES `ours` as two fitted constants","risk":"low","why":"the old note here said the row was 'not reachable from a ServerPlayer'. That was wrong: the record is at ServerPlayer+0x36c and every consumer calls DifficultyMods_Select(p->+0x36c, p). Lane L5 now snapshots it and emits it as `inputs.live_difficulty` alongside the fitted pair, so a run SHOWS whether the fit is right instead of assuming it. `ours` was deliberately left on the fitted constants so that this run is evidence about them; switching it over is the next lane's one-line change","mitigation":"logged as `inputs.live_difficulty` on every record"},{"what":"three of the four float widths this routine turns on are unexercised by any reference turn","risk":"medium","why":"the savings-interest rate is a widened 0.01f and its boundary IS in the corpus (a treasury of 50,000 earns 499, not 500). The research yield factor is a widened 0.85f whose boundary needs a research money that is a multiple of 40,000, and the three research modifiers are summed in SINGLE precision, which needs two of them non-zero -- the corpus has shrm = TRM = 0. So a green compare here verifies one of the three and says nothing about the other two","mitigation":"the record carries `inputs.live_consts` so the widths are readable, and tests/game_sim/test_economy.cpp pins all three at their boundaries"},{"what":"the research-allocation vector's heap block","risk":"low","why":"only the element count is compared; the three words are heap pointers the default policy ignores","mitigation":""}]}},"Game::WeaponDictionary::Init":{"ftol":0,"ftol_kind":"abs","ptr":"ignore","coverage":{"state":"partial","why":"","unmodelled":[{"what":"LoadWeapon -> WeaponDef::ParseScript registers each weapon's name with the string table and resolves `requires` against the live TechTree","risk":"high","why":"per-file parsing is M3 scope; ours delegates to the game's own LoadWeapon, so a compare run performs the registration a SECOND time and neither the string table nor the tech tree is a declared region","mitigation":"suspected cause of the sibling section hook's compare crash (docs/M2.md)"},{"what":"allocates 123 WeaponDef objects (0x278 bytes each) on the game heap","risk":"low","why":"the definitions do not exist when the hook is entered, so they cannot be a before-snapshot; the dictionary region compares them by id/name/path","mitigation":""},{"what":"the word at dictionary+0x14","risk":"low","why":"not modelled; emitted as an opaque pointer, which the default policy ignores -- a change is visible in a trace but never a divergence","mitigation":"guard:dict"},{"what":"writes lines to the game log for a missing manifest","risk":"low","why":"log text is not simulation state","mitigation":""},{"what":"std::sort tie order for equal weapon names","risk":"low","why":"msvc_sort.h replays MSVC 2010's introsort, but the shipped data has no tied names, so the tie rule is unexercised rather than verified","mitigation":""}]}},"Game::SectionDictionary::SectionDictionary":{"ftol":0,"ftol_kind":"abs","ptr":"ignore","coverage":{"state":"partial","why":"","unmodelled":[{"what":"LoadSection registers each section with the string table and the live TechTree, and may append to the dictionary's own vector","risk":"high","why":"M3 scope; ours delegates to the game's LoadSection after the original has already built all 885 definitions, so the second pass registers duplicates -- the leading hypothesis for this hook's compare-mode crash","mitigation":"see docs/M2.md; compare mode for this hook is not safe to run"},{"what":"post-load validation pass over every definition's @-token against the string table","risk":"medium","why":"runs after the loop and touches no declared region","mitigation":""},{"what":"allocates 885 SectionDef objects (0x3d8 bytes each) on the game heap","risk":"low","why":"they do not exist at hook entry; compared by index/species/id/token","mitigation":""},{"what":"the word at dictionary+0x14","risk":"low","why":"not modelled; emitted as an ignored pointer","mitigation":"guard:dict"},{"what":"the before-snapshot of the object is uninitialised heap","risk":"medium","why":"the hook is on the constructor, so `before` is meaningless and only `after` carries information","mitigation":""}]}},"Game::TechTree::ProcessResearch":{"ftol":0,"ftol_kind":"abs","ptr":"ignore","coverage":{"state":"partial","why":"","unmodelled":[{"what":"posts EVENT_RESEARCH_OVERBUDGET on the owner's EventStorage: ours reproduces the decision and the id sequence, so region:events compares next_id, but the composed EvDsc/EvMsg text is not reproduced and no region can see it","risk":"medium","why":"text comes from the game's string table, which the engine must not carry; ours posts into its own EventStorage and writes only the counts into the scratch copy, so no live byte moves and replace mode posts nothing at all","mitigation":"region:events"},{"what":"composes EVENT_TECHS_UNLOCKED's message from the unlocked techs' names","risk":"low","why":"the trigger and the list are modelled (SetResearched's availability sweep plus the tail collector, both read off the instruction stream), so region:events compares next_id; the names come from the game's string table, so the message is composed from node indices instead and is not the game's text","mitigation":"region:events"},{"what":"TechTree::SetResearched in REPLACE mode: nothing of it runs","risk":"high","why":"the cascade is compare-mode only. In replace mode every pointer is live game memory, and applying half of OnTechResearched -- the observed-tech append and the research-event roll, but not the tech-effect field writes -- would leave the player in a state no code path produces. A replace run therefore still leaves the completed node unstamped and no tech unlocked","mitigation":"guard:player, guard:tree_header"},{"what":"ServerPlayer::OnTechResearched's tech effects: the ~90 hard-coded ServerPlayer field writes, the plague-cure masks, the design-option bitmasks and the species tech flags","risk":"high","why":"B2's milestone. `ours` models only the two parts of the callback this hook's regions can see -- the observed-tech append and the RNG word RollResearchEvent draws before its branch (one word on a missed roll, two on a fired plague roll) -- and the rest is what the player guard reports","mitigation":"guard:player"},{"what":"the research-event branch RollResearchEvent takes when its roll beats the odds (ServerPlayer::OnResearchRollSucceeded: the plague and AI-rebellion event paths)","risk":"high","why":"RollResearchEvent draws one NextFloat unconditionally and that draw IS modelled -- but that is only the cost of REACHING the branch. A FIRED roll costs one or two words: the plague path draws a SECOND word (NextInt) to pick an owned system and posts EVENT_PLAGUE_OUTBREAK, while the rebellion path allocates an AIRebellion at ServerPlayer+0x3b8 and CANCELS the current research (no further draw). The branch is entered only for the plague and AI-rebellion tech families, whose odds are 0 everywhere else, and it has never been observed firing in three sessions -- which is why every earlier note in this repo said 'exactly one NextFloat' and nothing caught it. If it is ever entered, region:rng is the check","mitigation":"region:rng"},{"what":"constructs the ObservedTech element it appends to ServerPlayer+0x274","risk":"medium","why":"`ours` models the append DECISION -- RecordObservedTech de-duplicates by tech name, so it decides whether the vector grows -- and moves the scratch header's byte span by one 0x2c element per append. The element's own fields (turn_first, turn_last, detected, the name string, `with`) are not built, and no region can see them","mitigation":"region:observed_techs"},{"what":"the tree's completion-order counter (TechTree+0x20) is read pre-call, not modelled as a region","risk":"low","why":"the per-node `order` word IS compared, and it is stamped from a counter `ours` seeds from the pre-call read and advances itself; the counter's own final value is only seen by the tree_header guard","mitigation":"guard:tree_header"},{"what":"writes a completion line to the game log","risk":"low","why":"log text is not simulation state","mitigation":""}]}},"Game::ServerPlayer::OnTechResearched":{"ftol":0,"ftol_kind":"abs","ptr":"ignore","coverage":{"state":"partial","why":"","unmodelled":[{"what":"posts EVENT_RESEARCH_COMPLETE / _UNDERBUDGET / _TEMPERANCE on the owner's EventStorage when !silent","risk":"high","why":"the same class of write as B3's defect, and this hook has no replace-mode oracle that could catch it: gotcha 4 in docs/B2.md says a changed save hash on a completion turn is expected and therefore not a finding","mitigation":"guard:player (EventStorage is inline at ServerPlayer+0x29c)"},{"what":"writes every owned system's AI flag (CCC_AIVrus / CCC_AISlv), re-evaluates the arcology civilian cap, cures addiction and clears plague across systems AND ships","risk":"high","why":"writes through pointers to other objects; compare mode must not touch live state, and no region reaches them","mitigation":""},{"what":"the pending plague-cure roll (ServerPlayer::RollResearchEvent)","risk":"high","why":"it draws one word from the strategic generator unconditionally, and a SECOND word (NextInt) when the roll beats the odds and takes the plague path -- which also posts EVENT_PLAGUE_OUTBREAK, while the rebellion path cancels the research. So a fired roll costs one or two words, not one; running it in compare mode would consume real randomness. The two words it guards are still cleared and the record says whether it would have fired","mitigation":"this is the extra draw B3 observed on a completion"},{"what":"TechTree::SetResearched for the Zuul boarding-pod grant","risk":"medium","why":"it would mutate the live tree, and it recurses","mitigation":""},{"what":"allocates or frees the node-bore block at ServerPlayer+0x308","risk":"medium","why":"ours has no allocator the game's runtime could free, so replace mode calls the game's own updater -- which means replace mode never exercises our node-bore selection at all","mitigation":"region:node_bore, declared only when the block already exists"}]}},"Game::ServerSystem::ProcessTurn":{"ftol":0,"ftol_kind":"abs","ptr":"ignore","coverage":{"state":"partial","why":"","unmodelled":[{"what":"the addiction sweep raises MoraleEvents, which are constructed and appended to the system's capped morale history","risk":"high","why":"the same class of write as B3's defect. sim::ProcessColonyTurn does compute the morale events (ColonyTurnResult), but the hook never emits them: DescribeMoraleEvents is dead code, so they are neither compared nor logged","mitigation":"guard:system"},{"what":"every callee: the plague pass, imperial and civilian growth, the resource debit, in-orbit refuel, slaves, rebellion and the build queue","risk":"high","why":"declared input boundary -- ProcessTurn is a dispatcher and only the words it writes itself are modelled. The callees raise EVENT_SLAVES_DEAD, EVENT_SYSTEM_REBELLION_CONTINUES, the plague events and SEBuildCompleted, create ships and bump per-player ShipRecords counters","mitigation":"guard:system covers the system object only, not the other objects"},{"what":"ApplyInfraBonus / ApplyPopBonus read the owner's home-system id, and the build queue writes the owning ServerPlayer","risk":"medium","why":"writes through a pointer to another object; no region reaches the player","mitigation":""},{"what":"ProcessRebellion is the pass's only RNG consumer and its draw count is data-dependent","risk":"low","why":"the generator IS a declared region, so a moved post-state is visible and names the system whose rebellion fired -- it is reported, not modelled","mitigation":""},{"what":"replace mode is refused for this hook","risk":"medium","why":"our side models the dispatcher's own writes and none of the callees, so a replace run would silently skip a colony's whole turn. There is therefore no oracle layer behind the compare for this hook","mitigation":""}]}},"Game::ServerSystem::GroupOutput":{"ftol":0,"ftol_kind":"abs","ptr":"ignore","coverage":{"state":"partial","why":"the imperial and civilian output modifiers, the 1.8 factor and the 500000 divisor are literals inside the executable, so nothing about them is assumed from the data files","unmodelled":[{"what":"the station count that scales the imperial term","risk":"high","why":"the original gets it from a helper that walks the system's fleets and their ships through virtual calls and takes the system in EBX, which a hook cannot call portably. `ours` therefore assumes ZERO stations. A divergence on an imperial row is expected to be exactly the station factor, and the record carries `count` and the return, so the factor is MEASURED from the trace rather than fitted","mitigation":"declared input boundary; the trace makes it recoverable"},{"what":"the slave row's output modifier, and every value the data files supply","risk":"medium","why":"SLAVES_OUTPUT_MOD, the two morale thresholds and their two modifiers, and STATION_BONUS_IMPERIAL_OUTPUT are read out of the live process's globals and logged with every record, so the record says which value drove it","mitigation":"logged as `tuning` on every record"}]}},"Game::ServerSystem::ComputeTotalOutput":{"ftol":0,"ftol_kind":"abs","ptr":"ignore","coverage":{"state":"partial","why":"","unmodelled":[{"what":"the station count, as for GroupOutput","risk":"high","why":"`ours` assumes zero stations, so a system with an imperial population and a station diverges by the station factor","mitigation":"declared input boundary"},{"what":"the slave population and its xenotech adjustment","risk":"high","why":"the original's slave count is not a plain field: it runs the count through a per-species xenotech factor. `ours` takes the slave term as ZERO, so any system holding slaves diverges. The record logs the raw group-2 population sums so a divergence can be attributed","mitigation":"declared input boundary"},{"what":"the capacity surplus the civilian term adds for the owner's own species","risk":"medium","why":"the original calls the carrying-capacity helper twice with different out-parameter slots and adds max(0, B - A) to the civilian count; `ours` uses the raw civilian population. The surplus is zero except when the colony is at its cap","mitigation":"declared input boundary"},{"what":"the addiction phase","risk":"low","why":"`ours` assumes it is below 3, so ADDICTION_OUTPUT_MOD never applies; the record logs the system's addiction table length so the case is visible","mitigation":""}]}},"Game::ServerPlayer::ProcessTurn":{"ftol":0,"ftol_kind":"abs","ptr":"ignore","coverage":{"state":"partial","why":"","unmodelled":[{"what":"phases 2, 3 and 6 -- the savings apply Sav = SatAdd(budget[0], net), the three aid/trade records copied out of the budget, and the research refund -- are NOT declared and NOT compared","risk":"high","why":"all three are pure functions of ComputeBudget's 22-slot output and of ProcessResearch's overBudget out-parameter, and both live in the original's own stack frame ([ebp-0x90] and [ebp-0x14]). The three ways to reach them are each worse than not having them: call ComputeBudget ourselves (it repairs damaged ships in orbit -- harness-audit #6), read them out of the nested B1/B3 hooks (harness-audit #5, the self-fulfilling compare), or infer them from the observed Sav delta (the same trap). The formulas ARE written and unit-tested in player_turn_inputs.cpp; they are simply not wired into the verdict","mitigation":"guard:player reports Sav, +0xc8 and +0xcc moving"},{"what":"ComputeBudget (0x00863030) itself, including ServerSystem::ComputeOutput, which REPAIRS DAMAGED SHIPS IN ORBIT","risk":"high","why":"B1 is the hook that checks the budget; its ship-repair side effect happens inside this call too, once per system per player per turn","mitigation":"run hook.Game::ServerPlayer::ComputeBudget=compare alongside"},{"what":"TechTree::ProcessResearch and the whole SetResearched / OnTechResearched cascade it can trigger: progress, the completion roll, the 5% decay sweep, the child-unlock cascade, ~90 tech-effect field writes, EVENT_RESEARCH_* and EVENT_TECHS_UNLOCKED","risk":"high","why":"declared input boundary. B3/U own it; this hook reports the pre-call research state and lets the player guard say how much moved","mitigation":"guard:player, and hook.Game::TechTree::ProcessResearch=compare"},{"what":"RollResearchAccident (0x00889dc0) draws Mars::RNG::NextInt(100) whenever the research boost is non-zero, can apply progress loss across EVERY system, and posts EVENT_LABACCIDENT_{SMALL,MEDIUM,LARGE}","risk":"high","why":"it runs before ProcessResearch and gates it entirely. Its draws move the declared `rng` region, so they are visible -- but as an unexplained RNG divergence, not as their cause","mitigation":"region:rng shows the draws; nothing shows the systems it wrote"},{"what":"the ResearchRollPending roll: RollResearchEvent draws one NextFloat, and when it BEATS the odds the plague branch draws a SECOND word (NextInt) and posts EVENT_PLAGUE_OUTBREAK, while the rebellion branch allocates an AIRebellion at ServerPlayer+0x3b8 and cancels the current research","risk":"high","why":"every previous coverage note in this repo says 'exactly one NextFloat'. That is the cost of REACHING the branch; a fired roll costs one or two words. The branch has never been observed firing. `predict_roll` says whether we expected the roll, `region:rng` says what it actually cost, and `roll_flags` says whether ResErrRoll was consumed","mitigation":"region:rng + region:roll_flags + guard:player; ours never rolls"},{"what":"ServerPlayer::ProcessSpecialProjects (0x00840fe0) and, for an AI player, ConstructionSpend (0x00817f90)","risk":"medium","why":"1015 bytes of special-project state, plus the log line \"SpecialProject: %s completed investigation phase\"","mitigation":"guard:player"},{"what":"the EVENT_NO_RESEARCH post at 0x0089168c, which appends to the player's EventStorage (+0x29c) and bumps EvNxID (+0x2b0)","risk":"medium","why":"B3's exact failure mode: a list append outside every Result region. Its condition is fully known (ResT == 0, nothing completed this turn, and at least one state-2 tech exists) but ours posts nothing","mitigation":"guard:player reports the EvNxID bump"},{"what":"PruneRaidTargets (0x00863cf0) erases from the heap vector at +0x338","risk":"low","why":"the vector header is inside the player guard, but its elements are heap memory no region reaches, and the erase runs each removed element's scalar destructor","mitigation":"guard:player sees the header move only"},{"what":"the timed-bonus element regions are captured from the PRE-CALL element addresses, and the sweep may shrink the vector under them","risk":"low","why":"erase moves data down inside the same buffer and only lowers _Mylast, so the addresses stay valid and readable. Elements past the new _Mylast are compared as stale bytes; `bonus_header` is the region that carries the count, and ours writes the same stale tail the original leaves","mitigation":"region:bonus_header"},{"what":"replace mode is refused for this hook","risk":"medium","why":"ours models the driver's own writes and none of ComputeBudget, ProcessResearch, ProcessSpecialProjects or the raid-target prune. A replace run would leave a player in a state no code path produces, and there is therefore no oracle layer behind this compare","mitigation":""}]}},"Game::StrategyServer::MoveFleet":{"ftol":0,"ftol_kind":"abs","ptr":"ignore","coverage":{"state":"partial","why":"","unmodelled":[{"what":"on arrival: dispatches SEFleetArrived and runs one of three arrival handlers by destination kind (enter system / join fleet / stop at point)","risk":"high","why":"declared input boundary -- an arriving call is expected to differ in all of it, and none of it is declared, so the compare says nothing about arrivals","mitigation":"guard:fleet sees the fleet's own words; the event and the system do not"},{"what":"on departure: cancels every still-acting ship (with a log line each) and calls ServerSystem::FleetDeparts, which rewrites the system's ownership bits","risk":"high","why":"writes through pointers to ships and to the system","mitigation":""},{"what":"the tanker top-up refuels other ships in the fleet","risk":"medium","why":"the per-ship range regions would show it, but ours does not model it, so a fleet with a tanker diverges for a known reason","mitigation":""},{"what":"a node-line waypoint's step comes from the stutter profile","risk":"medium","why":"NodeLineStep / BuildStutterSegments are written and unit-tested but not wired in; the hook steps every waypoint type as speed x dt, so a node-line leg is knowingly mis-stepped and only its type is recorded","mitigation":"declared gap: docs/B4.md"},{"what":"a missed probabilistic jump scatters the fleet in a random direction","risk":"medium","why":"the direction is a second draw whose mapping is not modelled; ours leaves the position alone and reports the scatter distance, so the generator region diverges by one word on a miss","mitigation":""},{"what":"the route revalidation and the waypoint list itself","risk":"medium","why":"declared input boundary; the waypoint vector is not a region","mitigation":""}]}},"Game::StrategyServer::ProcessFleetMovement":{"ftol":0,"ftol_kind":"abs","ptr":"ignore","coverage":{"state":"partial","why":"","unmodelled":[{"what":"`ours` re-reads the LIVE fleet list after the original has run","risk":"high","why":"the gate-traffic total is computed by the original at the very end of the pass, so a pre-call snapshot would diverge for the wrong reason. It breaks the compare invariant that ours never touches live memory, and it makes this hook's verdict partly self-fulfilling: the input to our arithmetic is the original's own post-move state","mitigation":""},{"what":"drives MoveFleet up to five times per fleet","risk":"high","why":"every undeclared effect of MoveFleet happens inside this call too; the pass schedule is recorded in the arguments but never compared","mitigation":""},{"what":"writes FPdpos into every fleet and clears flags 0x2 and 0x100 on every fleet","risk":"high","why":"no region covers the fleets, only the players' gate-traffic words","mitigation":""},{"what":"OnFleetArrived posts EVENT_FLEET_ARRIVED","risk":"high","why":"the same class of write as B3's defect, and there is no replace mode for this hook, so nothing behind the compare could catch it either","mitigation":""},{"what":"the original accumulates by player->index but writes back by the player's position in the server vector, into a fixed 32-int array with no bounds check","risk":"medium","why":"a real latent bug in the original that our side reproduces only while index == position; the reference save never separates them","mitigation":""},{"what":"PassSchedule() is never called by the hook, and FleetSummary::targetFleetId / relation are never filled","risk":"medium","why":"the header claims ours predicts the call order for a trace to check; that prediction is not actually emitted","mitigation":""}]}},"Game::StrategyHost::Autosave":{"ftol":0,"ftol_kind":"abs","ptr":"ignore","coverage":{"state":"partial","why":"","unmodelled":[{"what":"everything the original writes except the strategic generator","risk":"high","why":"this hook family measures ONE thing -- how many words the generator advances and where. It declares no region over game state and makes no claim about it. A clean run here says the RNG accounting is right and says nothing whatever about whether the turn was computed correctly","mitigation":"region:rng is the only check; the turn's own correctness is B1/B3/B4's job"},{"what":"the ledger reports WORDS, not draws","risk":"low","why":"a NextInt that rejects three times is four words and one call. Words are the unit that decides whether a save reproduces; they are the wrong unit for counting decisions, and nothing here should be read as a draw count","mitigation":"region:rng carries left/block/words, never a call count"},{"what":"the ledger is deliberately blind to WHICH primitive spent a word","risk":"low","why":"that is the design, and it is why this instrument was preferred to hooking the primitives: the image has FOUR draw entry points (NextFloat 0x0047d830, NextInt 0x004271c0, Chance 0x008e6dd0 and NextUInt 0x004f7670, the last of which appears in no previous lane's primitive set) plus inlined draws in at least twelve functions, two of them reachable from the turn roots. A primitive-counting hook would have silently undercounted every one of those","mitigation":"region:rng reads the state, so an inlined draw is as visible as a called one"},{"what":"a generator position the ledger cannot place reads `words: null`","risk":"medium","why":"a block more than 4096 twists ahead of the frontier, or any state behind the anchor, is reported unknown rather than guessed. A null in a ledger field is a measurement failure and must not be read as zero","mitigation":"region:rng emits null explicitly; tracecmp shows it as a value, not a gap"},{"what":"the whole save write: four path buffers, the ENDTURN pair removal, the backup rotation, the per-player connection detach/reattach, and SaveGame_WriteFile 0x00877070 itself","risk":"low","why":"this hook exists to timestamp the generator at the two moments the two save files are written. It is a marker and models nothing","mitigation":"region:rng only"},{"what":"the generator is reached through a CACHED StrategyServer pointer, not from this call's own arguments","risk":"medium","why":"`this` is the global at 0x00b29f98, hardcoded by both call sites, and no argument here names the server. On the first pre-turn autosave after a load no turn driver has run yet, so the cache is empty and that record carries no ledger position -- the FIRST BRACKET OF A SESSION IS INCOMPLETE BY CONSTRUCTION and must not be read as a zero-cost turn","mitigation":"arg:server_cached / host_plus_0x54 / server_agrees say which pointer was used and whether the +0x54 candidate is the same object"}]}},"Game::StrategyServer::ProcessTurn":{"ftol":0,"ftol_kind":"abs","ptr":"ignore","coverage":{"state":"partial","why":"","unmodelled":[{"what":"everything the original writes except the strategic generator","risk":"high","why":"this hook family measures ONE thing -- how many words the generator advances and where. It declares no region over game state and makes no claim about it. A clean run here says the RNG accounting is right and says nothing whatever about whether the turn was computed correctly","mitigation":"region:rng is the only check; the turn's own correctness is B1/B3/B4's job"},{"what":"the ledger reports WORDS, not draws","risk":"low","why":"a NextInt that rejects three times is four words and one call. Words are the unit that decides whether a save reproduces; they are the wrong unit for counting decisions, and nothing here should be read as a draw count","mitigation":"region:rng carries left/block/words, never a call count"},{"what":"the ledger is deliberately blind to WHICH primitive spent a word","risk":"low","why":"that is the design, and it is why this instrument was preferred to hooking the primitives: the image has FOUR draw entry points (NextFloat 0x0047d830, NextInt 0x004271c0, Chance 0x008e6dd0 and NextUInt 0x004f7670, the last of which appears in no previous lane's primitive set) plus inlined draws in at least twelve functions, two of them reachable from the turn roots. A primitive-counting hook would have silently undercounted every one of those","mitigation":"region:rng reads the state, so an inlined draw is as visible as a called one"},{"what":"a generator position the ledger cannot place reads `words: null`","risk":"medium","why":"a block more than 4096 twists ahead of the frontier, or any state behind the anchor, is reported unknown rather than guessed. A null in a ledger field is a measurement failure and must not be read as zero","mitigation":"region:rng emits null explicitly; tracecmp shows it as a value, not a gap"},{"what":"no model of the turn's RNG cost: 32 phases, each of which may draw","risk":"high","why":"ProcessResearch's completion roll, RollResearchAccident's NextInt(100), the ResearchRollPending roll (one word, or two on the plague path), and whatever ProcessStations / ProcessSurrenders / ProcessMissions / ProcessSpecialProjects spend -- none of which has ever been measured. `ours` predicts nothing and the record reports the measurement","mitigation":"region:rng measures the total; the per-phase split is not resolved here"},{"what":"this hook takes the address the fpu module also wants to sample","risk":"low","why":"MinHook allows one hook per target. `fpu.sample_turn=off` releases StrategyServer::ProcessTurn so this hook can install; with it on, this hook fails to install and the trace is missing half the ledger","mitigation":"shim.log records the MH_CreateHook status for both"}]}},"Game::StrategyServer::OnAllCombatDone_Tail":{"ftol":0,"ftol_kind":"abs","ptr":"ignore","coverage":{"state":"partial","why":"","unmodelled":[{"what":"everything the original writes except the strategic generator","risk":"high","why":"this hook family measures ONE thing -- how many words the generator advances and where. It declares no region over game state and makes no claim about it. A clean run here says the RNG accounting is right and says nothing whatever about whether the turn was computed correctly","mitigation":"region:rng is the only check; the turn's own correctness is B1/B3/B4's job"},{"what":"the ledger reports WORDS, not draws","risk":"low","why":"a NextInt that rejects three times is four words and one call. Words are the unit that decides whether a save reproduces; they are the wrong unit for counting decisions, and nothing here should be read as a draw count","mitigation":"region:rng carries left/block/words, never a call count"},{"what":"the ledger is deliberately blind to WHICH primitive spent a word","risk":"low","why":"that is the design, and it is why this instrument was preferred to hooking the primitives: the image has FOUR draw entry points (NextFloat 0x0047d830, NextInt 0x004271c0, Chance 0x008e6dd0 and NextUInt 0x004f7670, the last of which appears in no previous lane's primitive set) plus inlined draws in at least twelve functions, two of them reachable from the turn roots. A primitive-counting hook would have silently undercounted every one of those","mitigation":"region:rng reads the state, so an inlined draw is as visible as a called one"},{"what":"a generator position the ledger cannot place reads `words: null`","risk":"medium","why":"a block more than 4096 twists ahead of the frontier, or any state behind the anchor, is reported unknown rather than guessed. A null in a ledger field is a measurement failure and must not be read as zero","mitigation":"region:rng emits null explicitly; tracecmp shows it as a value, not a gap"},{"what":"36 phases, of which two can draw and neither is modelled here","risk":"high","why":"phase 6 reaches the unread 7499-byte combat resolver 0x007d5af0 (NextInt on the node-cannon path, Twist plus NextInt on the salvage path) and phase 11 draws one word per expired node line. `predict_nodeline_words` covers only the second, and the nested ApplyEncounterResult / NodeLineDecay hooks are what attribute the split","mitigation":"region:rng plus the two nested hooks"},{"what":"whether this handler runs on a turn with NO combat is what this hook is here to settle, and until it has run it is a hypothesis","risk":"medium","why":"combat-done-tail.md \u00c2\u00a76 infers it from the determinism note -- the post-turn autosave appears on every End Turn and this handler is its only reachable caller -- not from the instruction stream","mitigation":"arg:encounters says how many encounters this call saw; a call with 0 settles it"}]}},"Game::StrategyServer::ApplyEncounterResult":{"ftol":0,"ftol_kind":"abs","ptr":"ignore","coverage":{"state":"partial","why":"","unmodelled":[{"what":"everything the original writes except the strategic generator","risk":"high","why":"this hook family measures ONE thing -- how many words the generator advances and where. It declares no region over game state and makes no claim about it. A clean run here says the RNG accounting is right and says nothing whatever about whether the turn was computed correctly","mitigation":"region:rng is the only check; the turn's own correctness is B1/B3/B4's job"},{"what":"the ledger reports WORDS, not draws","risk":"low","why":"a NextInt that rejects three times is four words and one call. Words are the unit that decides whether a save reproduces; they are the wrong unit for counting decisions, and nothing here should be read as a draw count","mitigation":"region:rng carries left/block/words, never a call count"},{"what":"the ledger is deliberately blind to WHICH primitive spent a word","risk":"low","why":"that is the design, and it is why this instrument was preferred to hooking the primitives: the image has FOUR draw entry points (NextFloat 0x0047d830, NextInt 0x004271c0, Chance 0x008e6dd0 and NextUInt 0x004f7670, the last of which appears in no previous lane's primitive set) plus inlined draws in at least twelve functions, two of them reachable from the turn roots. A primitive-counting hook would have silently undercounted every one of those","mitigation":"region:rng reads the state, so an inlined draw is as visible as a called one"},{"what":"a generator position the ledger cannot place reads `words: null`","risk":"medium","why":"a block more than 4096 twists ahead of the frontier, or any state behind the anchor, is reported unknown rather than guessed. A null in a ledger field is a measurement failure and must not be read as zero","mitigation":"region:rng emits null explicitly; tracecmp shows it as a value, not a gap"},{"what":"the combat resolver 0x007d5af0 (7499 B) is completely unread","risk":"high","why":"this hook measures what its subtree spends and models none of it. Nothing about combat determinism can be settled until that function is read; this only puts a number on the hole","mitigation":"region:rng measures the subtotal"},{"what":"the ~0xea0-byte combat report, the CombatReport list append at S+0x1fc, the ClientEncounterResults push into S+0x2f4, the per-ship turn stamps and the pairwise engagement bits","risk":"medium","why":"all of it is game state this hook does not declare and does not check","mitigation":""}]}},"Game::StrategyServer::NodeLineDecay":{"ftol":0,"ftol_kind":"abs","ptr":"ignore","coverage":{"state":"partial","why":"","unmodelled":[{"what":"everything the original writes except the strategic generator","risk":"high","why":"this hook family measures ONE thing -- how many words the generator advances and where. It declares no region over game state and makes no claim about it. A clean run here says the RNG accounting is right and says nothing whatever about whether the turn was computed correctly","mitigation":"region:rng is the only check; the turn's own correctness is B1/B3/B4's job"},{"what":"the ledger reports WORDS, not draws","risk":"low","why":"a NextInt that rejects three times is four words and one call. Words are the unit that decides whether a save reproduces; they are the wrong unit for counting decisions, and nothing here should be read as a draw count","mitigation":"region:rng carries left/block/words, never a call count"},{"what":"the ledger is deliberately blind to WHICH primitive spent a word","risk":"low","why":"that is the design, and it is why this instrument was preferred to hooking the primitives: the image has FOUR draw entry points (NextFloat 0x0047d830, NextInt 0x004271c0, Chance 0x008e6dd0 and NextUInt 0x004f7670, the last of which appears in no previous lane's primitive set) plus inlined draws in at least twelve functions, two of them reachable from the turn roots. A primitive-counting hook would have silently undercounted every one of those","mitigation":"region:rng reads the state, so an inlined draw is as visible as a called one"},{"what":"a generator position the ledger cannot place reads `words: null`","risk":"medium","why":"a block more than 4096 twists ahead of the frontier, or any state behind the anchor, is reported unknown rather than guessed. A null in a ledger field is a measurement failure and must not be read as zero","mitigation":"region:rng emits null explicitly; tracecmp shows it as a value, not a gap"},{"what":"the collapse itself: 0x007a92e0 (690 B) and 0x007a4700 (2244 B) destroy or halt fleets and post EVENT_NODEDECAY_FLEET_DESTROYED_VIANODE / _HALTED / _HALTED_VIANODE, and loop 3 posts two more decay-stage events","risk":"high","why":"ours advances the generator and writes nothing else. In compare mode that is the intent -- the check is the word count -- but it means a clean verdict here says nothing about which lines actually collapsed","mitigation":"region:rng only"},{"what":"the draw-count model is verified by a DIRECT-call sweep of the downstream pair; their subtrees contain unresolved indirect call sites","risk":"medium","why":"if one of those vtable slots reaches a generator, the measured delta will exceed `predict_words` and this hook will diverge -- which is the correct outcome, and the reason the prediction is recorded as an argument","mitigation":"arg:predict_words vs region:rng is exactly that check"},{"what":"the expiry formula reproduces a signed idiv on nptf/npdtf without knowing whether nptf can be negative","risk":"low","why":"the original never sign-checks the traffic accumulator. The model truncates toward zero the same way; if the field is always non-negative the question never arises, and no save has been observed with a negative one","mitigation":""}]}},"Game::StrategyServer::ProcessNodeSpaceTravel":{"ftol":0,"ftol_kind":"abs","ptr":"ignore","coverage":{"state":"partial","why":"","unmodelled":[{"what":"everything the original writes except the strategic generator","risk":"high","why":"this hook family measures ONE thing -- how many words the generator advances and where. It declares no region over game state and makes no claim about it. A clean run here says the RNG accounting is right and says nothing whatever about whether the turn was computed correctly","mitigation":"region:rng is the only check; the turn's own correctness is B1/B3/B4's job"},{"what":"the ledger reports WORDS, not draws","risk":"low","why":"a NextInt that rejects three times is four words and one call. Words are the unit that decides whether a save reproduces; they are the wrong unit for counting decisions, and nothing here should be read as a draw count","mitigation":"region:rng carries left/block/words, never a call count"},{"what":"the ledger is deliberately blind to WHICH primitive spent a word","risk":"low","why":"that is the design, and it is why this instrument was preferred to hooking the primitives: the image has FOUR draw entry points (NextFloat 0x0047d830, NextInt 0x004271c0, Chance 0x008e6dd0 and NextUInt 0x004f7670, the last of which appears in no previous lane's primitive set) plus inlined draws in at least twelve functions, two of them reachable from the turn roots. A primitive-counting hook would have silently undercounted every one of those","mitigation":"region:rng reads the state, so an inlined draw is as visible as a called one"},{"what":"a generator position the ledger cannot place reads `words: null`","risk":"medium","why":"a block more than 4096 twists ahead of the frontier, or any state behind the anchor, is reported unknown rather than guessed. A null in a ledger field is a measurement failure and must not be read as zero","mitigation":"region:rng emits null explicitly; tracecmp shows it as a value, not a gap"},{"what":"2945 bytes of node-space movement, entirely unmodelled and never swept for RNG by any lane","risk":"medium","why":"it is hooked here only because it runs TWICE a turn -- ProcessTurn phase 7 and tail phase 10 -- so a draw inside it would be double-counted by anyone modelling it once. The record says whether it draws at all","mitigation":"region:rng"}]}},"Game::EncounterDetect::AssignContacts":{"ftol":0,"ftol_kind":"abs","ptr":"ignore","coverage":{"state":"partial","why":"","unmodelled":[{"what":"everything the original writes except the strategic generator","risk":"high","why":"this hook family measures ONE thing -- how many words the generator advances and where. It declares no region over game state and makes no claim about it. A clean run here says the RNG accounting is right and says nothing whatever about whether the turn was computed correctly","mitigation":"region:rng is the only check; the turn's own correctness is B1/B3/B4's job"},{"what":"the ledger reports WORDS, not draws","risk":"low","why":"a NextInt that rejects three times is four words and one call. Words are the unit that decides whether a save reproduces; they are the wrong unit for counting decisions, and nothing here should be read as a draw count","mitigation":"region:rng carries left/block/words, never a call count"},{"what":"the ledger is deliberately blind to WHICH primitive spent a word","risk":"low","why":"that is the design, and it is why this instrument was preferred to hooking the primitives: the image has FOUR draw entry points (NextFloat 0x0047d830, NextInt 0x004271c0, Chance 0x008e6dd0 and NextUInt 0x004f7670, the last of which appears in no previous lane's primitive set) plus inlined draws in at least twelve functions, two of them reachable from the turn roots. A primitive-counting hook would have silently undercounted every one of those","mitigation":"region:rng reads the state, so an inlined draw is as visible as a called one"},{"what":"a generator position the ledger cannot place reads `words: null`","risk":"medium","why":"a block more than 4096 twists ahead of the frontier, or any state behind the anchor, is reported unknown rather than guessed. A null in a ledger field is a measurement failure and must not be read as zero","mitigation":"region:rng emits null explicitly; tracecmp shows it as a value, not a gap"},{"what":"the contact-to-detector assignment itself, and the two-pass outer loop","risk":"medium","why":"this hook exists because the draw here is INLINED and therefore invisible to every call-graph sweep and to the entry-point detours -- it is the one site in ProcessTurn's closure that neither instrument can see. It measures the word cost of the whole call and models nothing","mitigation":"region:rng; arg:detectors/contacts/max_trials bound the expected count"},{"what":"the per-trial threshold is 0.25f or 0.0f depending on two tech lookups, and the accept test short-circuits the inner loop","risk":"low","why":"so the measured cost is between |contacts| and |contacts| x |detectors| and the exact number depends on tech state this hook does not read","mitigation":"arg:max_trials is the upper bound only"}]}},"Game::EncounterDetect::ProcessTeamRecord":{"ftol":0,"ftol_kind":"abs","ptr":"ignore","coverage":{"state":"partial","why":"","unmodelled":[{"what":"everything the original writes except the strategic generator","risk":"high","why":"this hook family measures ONE thing -- how many words the generator advances and where. It declares no region over game state and makes no claim about it. A clean run here says the RNG accounting is right and says nothing whatever about whether the turn was computed correctly","mitigation":"region:rng is the only check; the turn's own correctness is B1/B3/B4's job"},{"what":"the ledger reports WORDS, not draws","risk":"low","why":"a NextInt that rejects three times is four words and one call. Words are the unit that decides whether a save reproduces; they are the wrong unit for counting decisions, and nothing here should be read as a draw count","mitigation":"region:rng carries left/block/words, never a call count"},{"what":"the ledger is deliberately blind to WHICH primitive spent a word","risk":"low","why":"that is the design, and it is why this instrument was preferred to hooking the primitives: the image has FOUR draw entry points (NextFloat 0x0047d830, NextInt 0x004271c0, Chance 0x008e6dd0 and NextUInt 0x004f7670, the last of which appears in no previous lane's primitive set) plus inlined draws in at least twelve functions, two of them reachable from the turn roots. A primitive-counting hook would have silently undercounted every one of those","mitigation":"region:rng reads the state, so an inlined draw is as visible as a called one"},{"what":"a generator position the ledger cannot place reads `words: null`","risk":"medium","why":"a block more than 4096 twists ahead of the frontier, or any state behind the anchor, is reported unknown rather than guessed. A null in a ledger field is a measurement failure and must not be read as zero","mitigation":"region:rng emits null explicitly; tracecmp shows it as a value, not a gap"},{"what":"the whole body of ProcessTeamRecord: the gate call, the two vector builds and the bucket construction","risk":"medium","why":"this hook measures the word cost of the call and recomputes three integers the original derives from the same record. It models none of the work and asserts nothing about the contact assignment","mitigation":"region:rng; arg:gate/pred_contacts/pred_detectors are a prediction, not a check"},{"what":"`+0xfc` and `+0xfb` are read as BYTES, following lane I's reading of the classifier functions","risk":"medium","why":"if either is really a wider field, every count here is wrong in the same direction and no cross-check inside this hook would notice. So the dword at +0xfc is read as well and any row where the two disagree is COUNTED, not silently resolved -- a non-zero disagreement count means the byte reading is unsafe on this workload","mitigation":"arg:fc_byte_vs_dword_disagreements; arg:entry_flags carries the raw values"},{"what":"an entry whose object pointer is unreadable is skipped","risk":"low","why":"it is not counted into any of the three classes, so entries != contacts + detectors + neither is the signal that this happened","mitigation":"arg:entries against the three class counts"}]}}}}} +{"ts":169848695,"hook":"Mars::RNG::Seed","mode":"trace","call_id":0,"thread":9080,"depth":0,"args":[{"t":"ptr","v":"0x0ddd49a0","n":"rng"},{"t":"u32","v":0,"n":"seed"},{"t":"bool","v":false,"n":"is_strategic_generator"}],"ret":{"t":"ptr","v":"0x0ddd49a0"},"side":{"rng":{"before":{"t":"struct","v":{"mt0":{"t":"u32","v":232436000},"mt1":{"t":"u32","v":0},"mt2":{"t":"u32","v":0},"mt623_left":{"t":"i32","v":0}}},"after":{"t":"struct","v":{"mt0":{"t":"u32","v":2443250962},"mt1":{"t":"u32","v":1093594115},"mt2":{"t":"u32","v":1878467924},"mt623_left":{"t":"i32","v":624}}}}}} +{"ts":169914800,"hook":"Mars::RNG::Seed","mode":"trace","call_id":1,"thread":9080,"depth":0,"args":[{"t":"ptr","v":"0x0ddb91d0","n":"rng"},{"t":"u32","v":3106153273,"n":"seed"},{"t":"bool","v":false,"n":"is_strategic_generator"}],"ret":{"t":"ptr","v":"0x0ddb91d0"},"side":{"rng":{"before":{"t":"struct","v":{"mt0":{"t":"u32","v":232953432},"mt1":{"t":"u32","v":1},"mt2":{"t":"u32","v":20},"mt623_left":{"t":"i32","v":69}}},"after":{"t":"struct","v":{"mt0":{"t":"u32","v":1070772451},"mt1":{"t":"u32","v":1803583385},"mt2":{"t":"u32","v":3890617576},"mt623_left":{"t":"i32","v":624}}}}}} +{"ts":224859871,"hook":"Mars::RNG::Seed","mode":"trace","call_id":3,"thread":9080,"depth":1,"args":[{"t":"ptr","v":"0x32af46f8","n":"rng"},{"t":"u32","v":2033976748,"n":"seed"},{"t":"bool","v":false,"n":"is_strategic_generator"}],"ret":{"t":"ptr","v":"0x32af46f8"},"side":{"rng":{"before":{"t":"struct","v":{"mt0":{"t":"u32","v":848368384},"mt1":{"t":"u32","v":1459791493},"mt2":{"t":"u32","v":263903821},"mt623_left":{"t":"i32","v":-968028171}}},"after":{"t":"struct","v":{"mt0":{"t":"u32","v":2109208335},"mt1":{"t":"u32","v":2833560095},"mt2":{"t":"u32","v":3945297956},"mt623_left":{"t":"i32","v":624}}}}}} +{"ts":224884012,"hook":"Game::StrategyApp::RunAI","mode":"trace","call_id":2,"thread":9080,"depth":0,"args":[{"t":"ptr","v":"0x00939f98","n":"app"},{"t":"i32","v":32,"n":"player_net_id"},{"t":"str","v":"SavedGames/ad-turn27-two-raiders.sav","n":"ai_data"},{"t":"u32","v":0,"n":"personality"},{"t":"u32","v":2033976748,"n":"rng_seed"}],"ret":null,"side":{}} +{"ts":224884162,"hook":"Mars::RNG::Seed","mode":"trace","call_id":5,"thread":9080,"depth":1,"args":[{"t":"ptr","v":"0x0ddeb210","n":"rng"},{"t":"u32","v":1705263844,"n":"seed"},{"t":"bool","v":false,"n":"is_strategic_generator"}],"ret":{"t":"ptr","v":"0x0ddeb210"},"side":{"rng":{"before":{"t":"struct","v":{"mt0":{"t":"u32","v":850221976},"mt1":{"t":"u32","v":0},"mt2":{"t":"u32","v":0},"mt623_left":{"t":"i32","v":0}}},"after":{"t":"struct","v":{"mt0":{"t":"u32","v":929562636},"mt1":{"t":"u32","v":2460387128},"mt2":{"t":"u32","v":3653784915},"mt623_left":{"t":"i32","v":624}}}}}} +{"ts":224903255,"hook":"Game::StrategyApp::RunAI","mode":"trace","call_id":4,"thread":9080,"depth":0,"args":[{"t":"ptr","v":"0x00939f98","n":"app"},{"t":"i32","v":496,"n":"player_net_id"},{"t":"str","v":"SavedGames/ad-turn27-two-raiders.sav","n":"ai_data"},{"t":"u32","v":0,"n":"personality"},{"t":"u32","v":1705263844,"n":"rng_seed"}],"ret":null,"side":{}} +{"ts":224903349,"hook":"Mars::RNG::Seed","mode":"trace","call_id":7,"thread":9080,"depth":1,"args":[{"t":"ptr","v":"0x32a8a4a8","n":"rng"},{"t":"u32","v":4254525491,"n":"seed"},{"t":"bool","v":false,"n":"is_strategic_generator"}],"ret":{"t":"ptr","v":"0x32a8a4a8"},"side":{"rng":{"before":{"t":"struct","v":{"mt0":{"t":"u32","v":232602856},"mt1":{"t":"u32","v":1575750400},"mt2":{"t":"u32","v":1158963209},"mt623_left":{"t":"i32","v":1529598571}}},"after":{"t":"struct","v":{"mt0":{"t":"u32","v":3228209554},"mt1":{"t":"u32","v":2835679022},"mt2":{"t":"u32","v":3785388244},"mt623_left":{"t":"i32","v":624}}}}}} +{"ts":224922388,"hook":"Game::StrategyApp::RunAI","mode":"trace","call_id":6,"thread":9080,"depth":0,"args":[{"t":"ptr","v":"0x00939f98","n":"app"},{"t":"i32","v":512,"n":"player_net_id"},{"t":"str","v":"SavedGames/ad-turn27-two-raiders.sav","n":"ai_data"},{"t":"u32","v":0,"n":"personality"},{"t":"u32","v":4254525491,"n":"rng_seed"}],"ret":null,"side":{}} +{"ts":280310107,"hook":"Game::StrategyHost::Autosave","mode":"trace","call_id":8,"thread":9080,"depth":0,"args":[{"t":"ptr","v":"0x00939f98","n":"host"},{"t":"ptr","v":"0x00cffb00","n":"out_name"},{"t":"bool","v":true,"n":"end_turn"},{"t":"ptr","v":"0x00000000","n":"server_cached"},{"t":"ptr","v":"0x03d284a8","n":"host_plus_0x54"},{"t":"bool","v":false,"n":"server_agrees"},{"t":"ptr","v":"0x00000000","n":"rng"},{"t":"null","v":null,"n":"rng_words_in"},{"t":"null","v":null,"n":"rng_left_in"}],"ret":{"t":"ptr","v":"0x00cffb00"},"side":{}} +{"ts":280367781,"hook":"Game::SVSOSwarmQueen::RegisterHives","mode":"trace","call_id":11,"thread":9080,"depth":2,"args":[{"t":"ptr","v":"0x03de72b0","n":"queen"},{"t":"i32","v":3,"n":"scenario_tag"},{"t":"i32","v":10,"n":"enc_id"},{"t":"i32","v":-1,"n":"hives_in"},{"t":"i32","v":-1,"n":"queens_in"},{"t":"null","v":null,"n":"hives"},{"t":"i32","v":28,"n":"systems"},{"t":"i32","v":0,"n":"systems_tagged"},{"t":"i32","v":0,"n":"predict_new_hives"},{"t":"i32","v":0,"n":"predict_min_words"},{"t":"struct","v":{"rva":{"t":"u32","v":7209476},"ptr":{"t":"u32","v":9553888},"value":{"t":"i32","v":20}},"n":"hive_nextq_lo"},{"t":"struct","v":{"rva":{"t":"u32","v":7209480},"ptr":{"t":"u32","v":9553892},"value":{"t":"i32","v":30}},"n":"hive_nextq_hi"},{"t":"ptr","v":"0x0ddd49a0","n":"rng"},{"t":"i64","v":575,"n":"rng_words_in"},{"t":"i32","v":49,"n":"rng_left_in"}],"ret":null,"side":{"rng":{"before":{"t":"struct","v":{"left":{"t":"i32","v":49},"index":{"t":"i32","v":575},"block":{"t":"i32","v":0},"words":{"t":"i64","v":575},"block_hash":{"t":"u64","v":"1498228442844855576"}}},"after":{"t":"struct","v":{"left":{"t":"i32","v":49},"index":{"t":"i32","v":575},"block":{"t":"i32","v":0},"words":{"t":"i64","v":575},"block_hash":{"t":"u64","v":"1498228442844855576"}}}}}} +{"ts":280368075,"hook":"Game::SVSOSwarmQueen::TickHives","mode":"trace","call_id":12,"thread":9080,"depth":2,"args":[{"t":"ptr","v":"0x03de72b0","n":"queen"},{"t":"i32","v":3,"n":"scenario_tag"},{"t":"i32","v":10,"n":"enc_id"},{"t":"i32","v":-1,"n":"hives_in"},{"t":"i32","v":-1,"n":"queens_in"},{"t":"null","v":null,"n":"hives"},{"t":"struct","v":{"rva":{"t":"u32","v":7209488},"ptr":{"t":"u32","v":9553900},"value":{"t":"i32","v":10}},"n":"gate_frame_floor"},{"t":"struct","v":{"rva":{"t":"u32","v":7209512},"ptr":{"t":"u32","v":9372196},"value":{"t":"i32","v":5}},"n":"gate_queen_age"},{"t":"struct","v":{"rva":{"t":"u32","v":7209504},"ptr":{"t":"u32","v":9372188},"value":{"t":"i32","v":3}},"n":"spawn_list_cap"},{"t":"bool","v":false,"n":"predict_gate1_fails"},{"t":"i32","v":0,"n":"predict_words"},{"t":"ptr","v":"0x0ddd49a0","n":"rng"},{"t":"i64","v":575,"n":"rng_words_in"},{"t":"i32","v":49,"n":"rng_left_in"}],"ret":null,"side":{"rng":{"before":{"t":"struct","v":{"left":{"t":"i32","v":49},"index":{"t":"i32","v":575},"block":{"t":"i32","v":0},"words":{"t":"i64","v":575},"block_hash":{"t":"u64","v":"1498228442844855576"}}},"after":{"t":"struct","v":{"left":{"t":"i32","v":49},"index":{"t":"i32","v":575},"block":{"t":"i32","v":0},"words":{"t":"i64","v":575},"block_hash":{"t":"u64","v":"1498228442844855576"}}}}}} +{"ts":280368183,"hook":"Game::SVSOSwarmQueen::OnTurnBegin","mode":"trace","call_id":10,"thread":9080,"depth":1,"args":[{"t":"ptr","v":"0x03de72b0","n":"queen"},{"t":"i32","v":3,"n":"scenario_tag"},{"t":"i32","v":10,"n":"enc_id"},{"t":"i32","v":-1,"n":"hives_in"},{"t":"i32","v":-1,"n":"queens_in"},{"t":"null","v":null,"n":"hives"},{"t":"ptr","v":"0x0ddd49a0","n":"rng"},{"t":"i64","v":575,"n":"rng_words_in"},{"t":"i32","v":49,"n":"rng_left_in"}],"ret":null,"side":{"rng":{"before":{"t":"struct","v":{"left":{"t":"i32","v":49},"index":{"t":"i32","v":575},"block":{"t":"i32","v":0},"words":{"t":"i64","v":575},"block_hash":{"t":"u64","v":"1498228442844855576"}}},"after":{"t":"struct","v":{"left":{"t":"i32","v":49},"index":{"t":"i32","v":575},"block":{"t":"i32","v":0},"words":{"t":"i64","v":575},"block_hash":{"t":"u64","v":"1498228442844855576"}}}}}} +{"ts":280368314,"hook":"Game::StrategyServer::BeginProcessTurn","mode":"trace","call_id":9,"thread":9080,"depth":0,"args":[{"t":"ptr","v":"0x0ddaade0","n":"server"},{"t":"i32","v":27,"n":"turn"},{"t":"i32","v":1428,"n":"phase_counter"},{"t":"i32","v":8,"n":"players"},{"t":"i32","v":-1,"n":"encounters"},{"t":"ptr","v":"0x0ddd49a0","n":"rng"},{"t":"i64","v":575,"n":"rng_words_in"},{"t":"i32","v":49,"n":"rng_left_in"}],"ret":null,"side":{"rng":{"before":{"t":"struct","v":{"left":{"t":"i32","v":49},"index":{"t":"i32","v":575},"block":{"t":"i32","v":0},"words":{"t":"i64","v":575},"block_hash":{"t":"u64","v":"1498228442844855576"}}},"after":{"t":"struct","v":{"left":{"t":"i32","v":49},"index":{"t":"i32","v":575},"block":{"t":"i32","v":0},"words":{"t":"i64","v":575},"block_hash":{"t":"u64","v":"1498228442844855576"}}}},"frame":{"before":{"t":"struct","v":{"value":{"t":"i32","v":27}}},"after":{"t":"struct","v":{"value":{"t":"i32","v":28}}}}}} +{"ts":280370413,"hook":"Game::StrategyServer::ProcessNodeSpaceTravel","mode":"trace","call_id":14,"thread":9080,"depth":1,"args":[{"t":"ptr","v":"0x0ddaade0","n":"server"},{"t":"i32","v":28,"n":"turn"},{"t":"i32","v":1496,"n":"phase_counter"},{"t":"i32","v":8,"n":"players"},{"t":"i32","v":-1,"n":"encounters"},{"t":"ptr","v":"0x0ddd49a0","n":"rng"},{"t":"i64","v":575,"n":"rng_words_in"},{"t":"i32","v":49,"n":"rng_left_in"}],"ret":null,"side":{"rng":{"before":{"t":"struct","v":{"left":{"t":"i32","v":49},"index":{"t":"i32","v":575},"block":{"t":"i32","v":0},"words":{"t":"i64","v":575},"block_hash":{"t":"u64","v":"1498228442844855576"}}},"after":{"t":"struct","v":{"left":{"t":"i32","v":49},"index":{"t":"i32","v":575},"block":{"t":"i32","v":0},"words":{"t":"i64","v":575},"block_hash":{"t":"u64","v":"1498228442844855576"}}}}}} +{"ts":280376347,"hook":"Game::StrategyServer::ProcessTurn","mode":"trace","call_id":13,"thread":9080,"depth":0,"args":[{"t":"ptr","v":"0x0ddaade0","n":"server"},{"t":"f32","v":1,"n":"dt"},{"t":"i32","v":28,"n":"turn"},{"t":"i32","v":1495,"n":"phase_counter"},{"t":"i32","v":8,"n":"players"},{"t":"i32","v":-1,"n":"encounters"},{"t":"ptr","v":"0x0ddd49a0","n":"rng"},{"t":"i64","v":575,"n":"rng_words_in"},{"t":"i32","v":49,"n":"rng_left_in"}],"ret":null,"side":{"rng":{"before":{"t":"struct","v":{"left":{"t":"i32","v":49},"index":{"t":"i32","v":575},"block":{"t":"i32","v":0},"words":{"t":"i64","v":575},"block_hash":{"t":"u64","v":"1498228442844855576"}}},"after":{"t":"struct","v":{"left":{"t":"i32","v":31},"index":{"t":"i32","v":593},"block":{"t":"i32","v":0},"words":{"t":"i64","v":593},"block_hash":{"t":"u64","v":"1498228442844855576"}}}}}} +{"ts":280420775,"hook":"Game::StrategyServer::ApplyEncounterResult","mode":"trace","call_id":16,"thread":9080,"depth":1,"args":[{"t":"ptr","v":"0x0ddaade0","n":"server"},{"t":"ptr","v":"0x32a1ac80","n":"encounter"},{"t":"ptr","v":"0x32a71fb0","n":"result"},{"t":"u8","v":1,"n":"res_no_battle"},{"t":"u8","v":0,"n":"res_peaceful"},{"t":"u8","v":0,"n":"res_surrendered"},{"t":"i32","v":28,"n":"turn"},{"t":"i32","v":1499,"n":"phase_counter"},{"t":"i32","v":8,"n":"players"},{"t":"i32","v":1,"n":"encounters"},{"t":"ptr","v":"0x0ddd49a0","n":"rng"},{"t":"i64","v":593,"n":"rng_words_in"},{"t":"i32","v":31,"n":"rng_left_in"}],"ret":null,"side":{"rng":{"before":{"t":"struct","v":{"left":{"t":"i32","v":31},"index":{"t":"i32","v":593},"block":{"t":"i32","v":0},"words":{"t":"i64","v":593},"block_hash":{"t":"u64","v":"1498228442844855576"}}},"after":{"t":"struct","v":{"left":{"t":"i32","v":31},"index":{"t":"i32","v":593},"block":{"t":"i32","v":0},"words":{"t":"i64","v":593},"block_hash":{"t":"u64","v":"1498228442844855576"}}}}}} +{"ts":280420951,"hook":"Game::StrategyServer::ProcessNodeSpaceTravel","mode":"trace","call_id":17,"thread":9080,"depth":1,"args":[{"t":"ptr","v":"0x0ddaade0","n":"server"},{"t":"i32","v":28,"n":"turn"},{"t":"i32","v":1499,"n":"phase_counter"},{"t":"i32","v":8,"n":"players"},{"t":"i32","v":0,"n":"encounters"},{"t":"ptr","v":"0x0ddd49a0","n":"rng"},{"t":"i64","v":593,"n":"rng_words_in"},{"t":"i32","v":31,"n":"rng_left_in"}],"ret":null,"side":{"rng":{"before":{"t":"struct","v":{"left":{"t":"i32","v":31},"index":{"t":"i32","v":593},"block":{"t":"i32","v":0},"words":{"t":"i64","v":593},"block_hash":{"t":"u64","v":"1498228442844855576"}}},"after":{"t":"struct","v":{"left":{"t":"i32","v":31},"index":{"t":"i32","v":593},"block":{"t":"i32","v":0},"words":{"t":"i64","v":593},"block_hash":{"t":"u64","v":"1498228442844855576"}}}}}} +{"ts":280421115,"hook":"Game::StrategyServer::NodeLineDecay","mode":"trace","call_id":18,"thread":9080,"depth":1,"args":[{"t":"ptr","v":"0x0ddaade0","n":"server"},{"t":"i32","v":28,"n":"turn"},{"t":"i32","v":1499,"n":"phase_counter"},{"t":"i32","v":8,"n":"players"},{"t":"i32","v":0,"n":"encounters"},{"t":"i32","v":51,"n":"node_paths"},{"t":"i32","v":51,"n":"np_permanent"},{"t":"i32","v":0,"n":"np_immortal"},{"t":"i32","v":0,"n":"np_mortal"},{"t":"i32","v":-1,"n":"np_min_life"},{"t":"i32","v":0,"n":"np_within5"},{"t":"i32","v":0,"n":"predict_words"},{"t":"ptr","v":"0x0ddd49a0","n":"rng"},{"t":"i64","v":593,"n":"rng_words_in"},{"t":"i32","v":31,"n":"rng_left_in"}],"ret":null,"side":{"rng":{"before":{"t":"struct","v":{"left":{"t":"i32","v":31},"index":{"t":"i32","v":593},"block":{"t":"i32","v":0},"words":{"t":"i64","v":593},"block_hash":{"t":"u64","v":"1498228442844855576"}}},"after":{"t":"struct","v":{"left":{"t":"i32","v":31},"index":{"t":"i32","v":593},"block":{"t":"i32","v":0},"words":{"t":"i64","v":593},"block_hash":{"t":"u64","v":"1498228442844855576"}}}}}} +{"ts":280421373,"hook":"Game::SVSOSlaversRefuel::UpdateDifficultyTier","mode":"trace","call_id":19,"thread":9080,"depth":1,"args":[{"t":"ptr","v":"0x03de7460","n":"slavers"},{"t":"i32","v":28,"n":"frame"},{"t":"i32","v":0,"n":"cdiff_in"},{"t":"list","v":[{"t":"i32","v":1},{"t":"i32","v":50},{"t":"i32","v":100}],"n":"thresholds"},{"t":"str","v":"no_store_unchanged","n":"predict_path"},{"t":"null","v":null,"n":"predict_cdiff_out"},{"t":"i32","v":0,"n":"predict_words"},{"t":"ptr","v":"0x0ddd49a0","n":"rng"},{"t":"i64","v":593,"n":"rng_words_in"},{"t":"i32","v":31,"n":"rng_left_in"}],"ret":null,"side":{"cdiff":{"before":{"t":"struct","v":{"value":{"t":"i32","v":0}}},"after":{"t":"struct","v":{"value":{"t":"i32","v":0}}}},"rng":{"before":{"t":"struct","v":{"left":{"t":"i32","v":31},"index":{"t":"i32","v":593},"block":{"t":"i32","v":0},"words":{"t":"i64","v":593},"block_hash":{"t":"u64","v":"1498228442844855576"}}},"after":{"t":"struct","v":{"left":{"t":"i32","v":31},"index":{"t":"i32","v":593},"block":{"t":"i32","v":0},"words":{"t":"i64","v":593},"block_hash":{"t":"u64","v":"1498228442844855576"}}}}}} +{"ts":280422502,"hook":"Game::StrategyServer::OnAllCombatDone_Tail","mode":"trace","call_id":15,"thread":9080,"depth":0,"args":[{"t":"ptr","v":"0x0ddaade0","n":"server"},{"t":"ptr","v":"0x32d5e67c","n":"results"},{"t":"i32","v":1,"n":"result_count"},{"t":"i32","v":28,"n":"turn"},{"t":"i32","v":1498,"n":"phase_counter"},{"t":"i32","v":8,"n":"players"},{"t":"i32","v":1,"n":"encounters"},{"t":"i32","v":51,"n":"node_paths"},{"t":"i32","v":51,"n":"np_permanent"},{"t":"i32","v":0,"n":"np_immortal"},{"t":"i32","v":0,"n":"np_mortal"},{"t":"i32","v":-1,"n":"np_min_life"},{"t":"i32","v":0,"n":"np_within5"},{"t":"i32","v":0,"n":"predict_nodeline_words"},{"t":"ptr","v":"0x0ddd49a0","n":"rng"},{"t":"i64","v":593,"n":"rng_words_in"},{"t":"i32","v":31,"n":"rng_left_in"}],"ret":null,"side":{"rng":{"before":{"t":"struct","v":{"left":{"t":"i32","v":31},"index":{"t":"i32","v":593},"block":{"t":"i32","v":0},"words":{"t":"i64","v":593},"block_hash":{"t":"u64","v":"1498228442844855576"}}},"after":{"t":"struct","v":{"left":{"t":"i32","v":29},"index":{"t":"i32","v":595},"block":{"t":"i32","v":0},"words":{"t":"i64","v":595},"block_hash":{"t":"u64","v":"1498228442844855576"}}}}}} +{"ts":280480019,"hook":"Game::StrategyHost::Autosave","mode":"trace","call_id":20,"thread":9080,"depth":0,"args":[{"t":"ptr","v":"0x00939f98","n":"host"},{"t":"ptr","v":"0x00cff8f0","n":"out_name"},{"t":"bool","v":false,"n":"end_turn"},{"t":"ptr","v":"0x0ddaade0","n":"server_cached"},{"t":"ptr","v":"0x03d284a8","n":"host_plus_0x54"},{"t":"bool","v":false,"n":"server_agrees"},{"t":"ptr","v":"0x0ddd49a0","n":"rng"},{"t":"i64","v":595,"n":"rng_words_in"},{"t":"i32","v":29,"n":"rng_left_in"},{"t":"list","v":[{"t":"struct","v":{"entry":{"t":"str","v":"Chance"},"ret_rva":{"t":"u32","v":3489164},"calls":{"t":"u32","v":14},"words":{"t":"u32","v":0},"no_draw_calls":{"t":"u32","v":14},"strategic":{"t":"bool","v":true}}},{"t":"struct","v":{"entry":{"t":"str","v":"NextFloat"},"ret_rva":{"t":"u32","v":5139977},"calls":{"t":"u32","v":16},"words":{"t":"u32","v":16},"no_draw_calls":{"t":"u32","v":0},"strategic":{"t":"bool","v":true}}},{"t":"struct","v":{"entry":{"t":"str","v":"Chance"},"ret_rva":{"t":"u32","v":4797483},"calls":{"t":"u32","v":8},"words":{"t":"u32","v":8},"no_draw_calls":{"t":"u32","v":0},"strategic":{"t":"bool","v":true}}},{"t":"struct","v":{"entry":{"t":"str","v":"Chance"},"ret_rva":{"t":"u32","v":4797720},"calls":{"t":"u32","v":8},"words":{"t":"u32","v":8},"no_draw_calls":{"t":"u32","v":0},"strategic":{"t":"bool","v":true}}},{"t":"struct","v":{"entry":{"t":"str","v":"NextFloat"},"ret_rva":{"t":"u32","v":1061538},"calls":{"t":"u32","v":1},"words":{"t":"u32","v":1},"no_draw_calls":{"t":"u32","v":0},"strategic":{"t":"bool","v":true}}},{"t":"struct","v":{"entry":{"t":"str","v":"NextInt"},"ret_rva":{"t":"u32","v":3746217},"calls":{"t":"u32","v":1},"words":{"t":"u32","v":1},"no_draw_calls":{"t":"u32","v":0},"strategic":{"t":"bool","v":true}}},{"t":"struct","v":{"entry":{"t":"str","v":"NextFloat"},"ret_rva":{"t":"u32","v":4328989},"calls":{"t":"u32","v":2},"words":{"t":"u32","v":2},"no_draw_calls":{"t":"u32","v":0},"strategic":{"t":"bool","v":true}}},{"t":"struct","v":{"entry":{"t":"str","v":"NextInt"},"ret_rva":{"t":"u32","v":1546517},"calls":{"t":"u32","v":3},"words":{"t":"u32","v":4},"no_draw_calls":{"t":"u32","v":0},"strategic":{"t":"bool","v":false}}},{"t":"struct","v":{"entry":{"t":"str","v":"NextFloat"},"ret_rva":{"t":"u32","v":5139977},"calls":{"t":"u32","v":1},"words":{"t":"u32","v":1},"no_draw_calls":{"t":"u32","v":0},"strategic":{"t":"bool","v":false}}},{"t":"struct","v":{"entry":{"t":"str","v":"Chance"},"ret_rva":{"t":"u32","v":1543445},"calls":{"t":"u32","v":1},"words":{"t":"u32","v":1},"no_draw_calls":{"t":"u32","v":0},"strategic":{"t":"bool","v":false}}},{"t":"struct","v":{"entry":{"t":"str","v":"NextInt"},"ret_rva":{"t":"u32","v":2743342},"calls":{"t":"u32","v":3},"words":{"t":"u32","v":3},"no_draw_calls":{"t":"u32","v":0},"strategic":{"t":"bool","v":false}}}],"n":"draw_sites"},{"t":"u32","v":36,"n":"draw_site_words"},{"t":"u32","v":50,"n":"draw_site_calls"},{"t":"u32","v":9,"n":"draw_site_words_other_rng"},{"t":"u32","v":8,"n":"draw_site_calls_other_rng"},{"t":"u32","v":0,"n":"draw_site_overflow"},{"t":"list","v":[{"t":"struct","v":{"name":{"t":"str","v":"Game::ServerSpyManager::vslot13"},"rva":{"t":"u32","v":4749232},"calls":{"t":"u32","v":1},"calls_since_launch":{"t":"u32","v":1},"installed":{"t":"bool","v":true}}},{"t":"struct","v":{"name":{"t":"str","v":"Game::ServerSpyManager::vslot14"},"rva":{"t":"u32","v":4774784},"calls":{"t":"u32","v":1},"calls_since_launch":{"t":"u32","v":1},"installed":{"t":"bool","v":true}}},{"t":"struct","v":{"name":{"t":"str","v":"Game::ServerTradeManagerImpl::vslot13"},"rva":{"t":"u32","v":4779904},"calls":{"t":"u32","v":1},"calls_since_launch":{"t":"u32","v":1},"installed":{"t":"bool","v":true}}},{"t":"struct","v":{"name":{"t":"str","v":"Game::ServerTradeManagerImpl::vslot15"},"rva":{"t":"u32","v":4377760},"calls":{"t":"u32","v":1},"calls_since_launch":{"t":"u32","v":1},"installed":{"t":"bool","v":true}}},{"t":"struct","v":{"name":{"t":"str","v":"Game::SpyManager::Slot13RngCallee"},"rva":{"t":"u32","v":4458720},"calls":{"t":"u32","v":0},"calls_since_launch":{"t":"u32","v":0},"installed":{"t":"bool","v":true}}},{"t":"struct","v":{"name":{"t":"str","v":"Game::TradeManager::Slot13RngCalleeA"},"rva":{"t":"u32","v":4328608},"calls":{"t":"u32","v":2},"calls_since_launch":{"t":"u32","v":2},"installed":{"t":"bool","v":true}}},{"t":"struct","v":{"name":{"t":"str","v":"Game::TradeManager::Slot13RngCalleeB"},"rva":{"t":"u32","v":4764736},"calls":{"t":"u32","v":1},"calls_since_launch":{"t":"u32","v":1},"installed":{"t":"bool","v":true}}},{"t":"struct","v":{"name":{"t":"str","v":"Game::ServerTradeManager::CreateRaidEncounter"},"rva":{"t":"u32","v":4798624},"calls":{"t":"u32","v":1},"calls_since_launch":{"t":"u32","v":1},"installed":{"t":"bool","v":true}}},{"t":"struct","v":{"name":{"t":"str","v":"Game::ServerTradeManager::GenerateTradeRaidEncounters"},"rva":{"t":"u32","v":4797072},"calls":{"t":"u32","v":0},"calls_since_launch":{"t":"u32","v":0},"installed":{"t":"bool","v":false}}},{"t":"struct","v":{"name":{"t":"str","v":"Game::ServerSpyManager::vslot15 [control]"},"rva":{"t":"u32","v":4751152},"calls":{"t":"u32","v":0},"calls_since_launch":{"t":"u32","v":0},"installed":{"t":"bool","v":false}}},{"t":"struct","v":{"name":{"t":"str","v":"Game::ServerTradeManagerImpl::vslot14 [control]"},"rva":{"t":"u32","v":4559056},"calls":{"t":"u32","v":0},"calls_since_launch":{"t":"u32","v":0},"installed":{"t":"bool","v":false}}},{"t":"struct","v":{"name":{"t":"str","v":"Game::EncounterDetect::Run [control]"},"rva":{"t":"u32","v":3977344},"calls":{"t":"u32","v":0},"calls_since_launch":{"t":"u32","v":0},"installed":{"t":"bool","v":false}}}],"n":"probe_entries"}],"ret":{"t":"ptr","v":"0x00cff8f0"},"side":{"rng":{"before":{"t":"struct","v":{"left":{"t":"i32","v":29},"index":{"t":"i32","v":595},"block":{"t":"i32","v":0},"words":{"t":"i64","v":595},"block_hash":{"t":"u64","v":"1498228442844855576"}}},"after":{"t":"struct","v":{"left":{"t":"i32","v":29},"index":{"t":"i32","v":595},"block":{"t":"i32","v":0},"words":{"t":"i64","v":595},"block_hash":{"t":"u64","v":"1498228442844855576"}}}}}} +{"ts":385005419,"hook":"Game::StrategyHost::Autosave","mode":"trace","call_id":21,"thread":9080,"depth":0,"args":[{"t":"ptr","v":"0x00939f98","n":"host"},{"t":"ptr","v":"0x00cffb00","n":"out_name"},{"t":"bool","v":true,"n":"end_turn"},{"t":"ptr","v":"0x0ddaade0","n":"server_cached"},{"t":"ptr","v":"0x03d284a8","n":"host_plus_0x54"},{"t":"bool","v":false,"n":"server_agrees"},{"t":"ptr","v":"0x0ddd49a0","n":"rng"},{"t":"i64","v":595,"n":"rng_words_in"},{"t":"i32","v":29,"n":"rng_left_in"}],"ret":{"t":"ptr","v":"0x00cffb00"},"side":{"rng":{"before":{"t":"struct","v":{"left":{"t":"i32","v":29},"index":{"t":"i32","v":595},"block":{"t":"i32","v":0},"words":{"t":"i64","v":595},"block_hash":{"t":"u64","v":"1498228442844855576"}}},"after":{"t":"struct","v":{"left":{"t":"i32","v":29},"index":{"t":"i32","v":595},"block":{"t":"i32","v":0},"words":{"t":"i64","v":595},"block_hash":{"t":"u64","v":"1498228442844855576"}}}}}} +{"ts":385056746,"hook":"Game::SVSOSwarmQueen::RegisterHives","mode":"trace","call_id":24,"thread":9080,"depth":2,"args":[{"t":"ptr","v":"0x03de72b0","n":"queen"},{"t":"i32","v":3,"n":"scenario_tag"},{"t":"i32","v":10,"n":"enc_id"},{"t":"i32","v":-1,"n":"hives_in"},{"t":"i32","v":-1,"n":"queens_in"},{"t":"null","v":null,"n":"hives"},{"t":"i32","v":28,"n":"systems"},{"t":"i32","v":0,"n":"systems_tagged"},{"t":"i32","v":0,"n":"predict_new_hives"},{"t":"i32","v":0,"n":"predict_min_words"},{"t":"struct","v":{"rva":{"t":"u32","v":7209476},"ptr":{"t":"u32","v":9553888},"value":{"t":"i32","v":20}},"n":"hive_nextq_lo"},{"t":"struct","v":{"rva":{"t":"u32","v":7209480},"ptr":{"t":"u32","v":9553892},"value":{"t":"i32","v":30}},"n":"hive_nextq_hi"},{"t":"ptr","v":"0x0ddd49a0","n":"rng"},{"t":"i64","v":595,"n":"rng_words_in"},{"t":"i32","v":29,"n":"rng_left_in"}],"ret":null,"side":{"rng":{"before":{"t":"struct","v":{"left":{"t":"i32","v":29},"index":{"t":"i32","v":595},"block":{"t":"i32","v":0},"words":{"t":"i64","v":595},"block_hash":{"t":"u64","v":"1498228442844855576"}}},"after":{"t":"struct","v":{"left":{"t":"i32","v":29},"index":{"t":"i32","v":595},"block":{"t":"i32","v":0},"words":{"t":"i64","v":595},"block_hash":{"t":"u64","v":"1498228442844855576"}}}}}} +{"ts":385056913,"hook":"Game::SVSOSwarmQueen::TickHives","mode":"trace","call_id":25,"thread":9080,"depth":2,"args":[{"t":"ptr","v":"0x03de72b0","n":"queen"},{"t":"i32","v":3,"n":"scenario_tag"},{"t":"i32","v":10,"n":"enc_id"},{"t":"i32","v":-1,"n":"hives_in"},{"t":"i32","v":-1,"n":"queens_in"},{"t":"null","v":null,"n":"hives"},{"t":"struct","v":{"rva":{"t":"u32","v":7209488},"ptr":{"t":"u32","v":9553900},"value":{"t":"i32","v":10}},"n":"gate_frame_floor"},{"t":"struct","v":{"rva":{"t":"u32","v":7209512},"ptr":{"t":"u32","v":9372196},"value":{"t":"i32","v":5}},"n":"gate_queen_age"},{"t":"struct","v":{"rva":{"t":"u32","v":7209504},"ptr":{"t":"u32","v":9372188},"value":{"t":"i32","v":3}},"n":"spawn_list_cap"},{"t":"bool","v":false,"n":"predict_gate1_fails"},{"t":"i32","v":0,"n":"predict_words"},{"t":"ptr","v":"0x0ddd49a0","n":"rng"},{"t":"i64","v":595,"n":"rng_words_in"},{"t":"i32","v":29,"n":"rng_left_in"}],"ret":null,"side":{"rng":{"before":{"t":"struct","v":{"left":{"t":"i32","v":29},"index":{"t":"i32","v":595},"block":{"t":"i32","v":0},"words":{"t":"i64","v":595},"block_hash":{"t":"u64","v":"1498228442844855576"}}},"after":{"t":"struct","v":{"left":{"t":"i32","v":29},"index":{"t":"i32","v":595},"block":{"t":"i32","v":0},"words":{"t":"i64","v":595},"block_hash":{"t":"u64","v":"1498228442844855576"}}}}}} +{"ts":385056975,"hook":"Game::SVSOSwarmQueen::OnTurnBegin","mode":"trace","call_id":23,"thread":9080,"depth":1,"args":[{"t":"ptr","v":"0x03de72b0","n":"queen"},{"t":"i32","v":3,"n":"scenario_tag"},{"t":"i32","v":10,"n":"enc_id"},{"t":"i32","v":-1,"n":"hives_in"},{"t":"i32","v":-1,"n":"queens_in"},{"t":"null","v":null,"n":"hives"},{"t":"ptr","v":"0x0ddd49a0","n":"rng"},{"t":"i64","v":595,"n":"rng_words_in"},{"t":"i32","v":29,"n":"rng_left_in"}],"ret":null,"side":{"rng":{"before":{"t":"struct","v":{"left":{"t":"i32","v":29},"index":{"t":"i32","v":595},"block":{"t":"i32","v":0},"words":{"t":"i64","v":595},"block_hash":{"t":"u64","v":"1498228442844855576"}}},"after":{"t":"struct","v":{"left":{"t":"i32","v":29},"index":{"t":"i32","v":595},"block":{"t":"i32","v":0},"words":{"t":"i64","v":595},"block_hash":{"t":"u64","v":"1498228442844855576"}}}}}} +{"ts":385057034,"hook":"Game::StrategyServer::BeginProcessTurn","mode":"trace","call_id":22,"thread":9080,"depth":0,"args":[{"t":"ptr","v":"0x0ddaade0","n":"server"},{"t":"i32","v":28,"n":"turn"},{"t":"i32","v":1499,"n":"phase_counter"},{"t":"i32","v":8,"n":"players"},{"t":"i32","v":0,"n":"encounters"},{"t":"ptr","v":"0x0ddd49a0","n":"rng"},{"t":"i64","v":595,"n":"rng_words_in"},{"t":"i32","v":29,"n":"rng_left_in"}],"ret":null,"side":{"rng":{"before":{"t":"struct","v":{"left":{"t":"i32","v":29},"index":{"t":"i32","v":595},"block":{"t":"i32","v":0},"words":{"t":"i64","v":595},"block_hash":{"t":"u64","v":"1498228442844855576"}}},"after":{"t":"struct","v":{"left":{"t":"i32","v":29},"index":{"t":"i32","v":595},"block":{"t":"i32","v":0},"words":{"t":"i64","v":595},"block_hash":{"t":"u64","v":"1498228442844855576"}}}},"frame":{"before":{"t":"struct","v":{"value":{"t":"i32","v":28}}},"after":{"t":"struct","v":{"value":{"t":"i32","v":29}}}}}} +{"ts":385058053,"hook":"Game::StrategyServer::ProcessNodeSpaceTravel","mode":"trace","call_id":27,"thread":9080,"depth":1,"args":[{"t":"ptr","v":"0x0ddaade0","n":"server"},{"t":"i32","v":29,"n":"turn"},{"t":"i32","v":1566,"n":"phase_counter"},{"t":"i32","v":8,"n":"players"},{"t":"i32","v":0,"n":"encounters"},{"t":"ptr","v":"0x0ddd49a0","n":"rng"},{"t":"i64","v":595,"n":"rng_words_in"},{"t":"i32","v":29,"n":"rng_left_in"}],"ret":null,"side":{"rng":{"before":{"t":"struct","v":{"left":{"t":"i32","v":29},"index":{"t":"i32","v":595},"block":{"t":"i32","v":0},"words":{"t":"i64","v":595},"block_hash":{"t":"u64","v":"1498228442844855576"}}},"after":{"t":"struct","v":{"left":{"t":"i32","v":29},"index":{"t":"i32","v":595},"block":{"t":"i32","v":0},"words":{"t":"i64","v":595},"block_hash":{"t":"u64","v":"1498228442844855576"}}}}}} +{"ts":385060739,"hook":"Game::StrategyServer::ProcessTurn","mode":"trace","call_id":26,"thread":9080,"depth":0,"args":[{"t":"ptr","v":"0x0ddaade0","n":"server"},{"t":"f32","v":1,"n":"dt"},{"t":"i32","v":29,"n":"turn"},{"t":"i32","v":1565,"n":"phase_counter"},{"t":"i32","v":8,"n":"players"},{"t":"i32","v":0,"n":"encounters"},{"t":"ptr","v":"0x0ddd49a0","n":"rng"},{"t":"i64","v":595,"n":"rng_words_in"},{"t":"i32","v":29,"n":"rng_left_in"}],"ret":null,"side":{"rng":{"before":{"t":"struct","v":{"left":{"t":"i32","v":29},"index":{"t":"i32","v":595},"block":{"t":"i32","v":0},"words":{"t":"i64","v":595},"block_hash":{"t":"u64","v":"1498228442844855576"}}},"after":{"t":"struct","v":{"left":{"t":"i32","v":9},"index":{"t":"i32","v":615},"block":{"t":"i32","v":0},"words":{"t":"i64","v":615},"block_hash":{"t":"u64","v":"1498228442844855576"}}}}}} +{"ts":385104631,"hook":"Game::StrategyServer::ApplyEncounterResult","mode":"trace","call_id":29,"thread":9080,"depth":1,"args":[{"t":"ptr","v":"0x0ddaade0","n":"server"},{"t":"ptr","v":"0x32a1ac80","n":"encounter"},{"t":"ptr","v":"0x32a72a68","n":"result"},{"t":"u8","v":1,"n":"res_no_battle"},{"t":"u8","v":0,"n":"res_peaceful"},{"t":"u8","v":0,"n":"res_surrendered"},{"t":"i32","v":29,"n":"turn"},{"t":"i32","v":1569,"n":"phase_counter"},{"t":"i32","v":8,"n":"players"},{"t":"i32","v":1,"n":"encounters"},{"t":"ptr","v":"0x0ddd49a0","n":"rng"},{"t":"i64","v":615,"n":"rng_words_in"},{"t":"i32","v":9,"n":"rng_left_in"}],"ret":null,"side":{"rng":{"before":{"t":"struct","v":{"left":{"t":"i32","v":9},"index":{"t":"i32","v":615},"block":{"t":"i32","v":0},"words":{"t":"i64","v":615},"block_hash":{"t":"u64","v":"1498228442844855576"}}},"after":{"t":"struct","v":{"left":{"t":"i32","v":9},"index":{"t":"i32","v":615},"block":{"t":"i32","v":0},"words":{"t":"i64","v":615},"block_hash":{"t":"u64","v":"1498228442844855576"}}}}}} +{"ts":385104850,"hook":"Game::StrategyServer::ProcessNodeSpaceTravel","mode":"trace","call_id":30,"thread":9080,"depth":1,"args":[{"t":"ptr","v":"0x0ddaade0","n":"server"},{"t":"i32","v":29,"n":"turn"},{"t":"i32","v":1569,"n":"phase_counter"},{"t":"i32","v":8,"n":"players"},{"t":"i32","v":0,"n":"encounters"},{"t":"ptr","v":"0x0ddd49a0","n":"rng"},{"t":"i64","v":615,"n":"rng_words_in"},{"t":"i32","v":9,"n":"rng_left_in"}],"ret":null,"side":{"rng":{"before":{"t":"struct","v":{"left":{"t":"i32","v":9},"index":{"t":"i32","v":615},"block":{"t":"i32","v":0},"words":{"t":"i64","v":615},"block_hash":{"t":"u64","v":"1498228442844855576"}}},"after":{"t":"struct","v":{"left":{"t":"i32","v":9},"index":{"t":"i32","v":615},"block":{"t":"i32","v":0},"words":{"t":"i64","v":615},"block_hash":{"t":"u64","v":"1498228442844855576"}}}}}} +{"ts":385104976,"hook":"Game::StrategyServer::NodeLineDecay","mode":"trace","call_id":31,"thread":9080,"depth":1,"args":[{"t":"ptr","v":"0x0ddaade0","n":"server"},{"t":"i32","v":29,"n":"turn"},{"t":"i32","v":1569,"n":"phase_counter"},{"t":"i32","v":8,"n":"players"},{"t":"i32","v":0,"n":"encounters"},{"t":"i32","v":51,"n":"node_paths"},{"t":"i32","v":51,"n":"np_permanent"},{"t":"i32","v":0,"n":"np_immortal"},{"t":"i32","v":0,"n":"np_mortal"},{"t":"i32","v":-1,"n":"np_min_life"},{"t":"i32","v":0,"n":"np_within5"},{"t":"i32","v":0,"n":"predict_words"},{"t":"ptr","v":"0x0ddd49a0","n":"rng"},{"t":"i64","v":615,"n":"rng_words_in"},{"t":"i32","v":9,"n":"rng_left_in"}],"ret":null,"side":{"rng":{"before":{"t":"struct","v":{"left":{"t":"i32","v":9},"index":{"t":"i32","v":615},"block":{"t":"i32","v":0},"words":{"t":"i64","v":615},"block_hash":{"t":"u64","v":"1498228442844855576"}}},"after":{"t":"struct","v":{"left":{"t":"i32","v":9},"index":{"t":"i32","v":615},"block":{"t":"i32","v":0},"words":{"t":"i64","v":615},"block_hash":{"t":"u64","v":"1498228442844855576"}}}}}} +{"ts":385105173,"hook":"Game::SVSOSlaversRefuel::UpdateDifficultyTier","mode":"trace","call_id":32,"thread":9080,"depth":1,"args":[{"t":"ptr","v":"0x03de7460","n":"slavers"},{"t":"i32","v":29,"n":"frame"},{"t":"i32","v":0,"n":"cdiff_in"},{"t":"list","v":[{"t":"i32","v":1},{"t":"i32","v":50},{"t":"i32","v":100}],"n":"thresholds"},{"t":"str","v":"no_store_unchanged","n":"predict_path"},{"t":"null","v":null,"n":"predict_cdiff_out"},{"t":"i32","v":0,"n":"predict_words"},{"t":"ptr","v":"0x0ddd49a0","n":"rng"},{"t":"i64","v":615,"n":"rng_words_in"},{"t":"i32","v":9,"n":"rng_left_in"}],"ret":null,"side":{"cdiff":{"before":{"t":"struct","v":{"value":{"t":"i32","v":0}}},"after":{"t":"struct","v":{"value":{"t":"i32","v":0}}}},"rng":{"before":{"t":"struct","v":{"left":{"t":"i32","v":9},"index":{"t":"i32","v":615},"block":{"t":"i32","v":0},"words":{"t":"i64","v":615},"block_hash":{"t":"u64","v":"1498228442844855576"}}},"after":{"t":"struct","v":{"left":{"t":"i32","v":9},"index":{"t":"i32","v":615},"block":{"t":"i32","v":0},"words":{"t":"i64","v":615},"block_hash":{"t":"u64","v":"1498228442844855576"}}}}}} +{"ts":385106215,"hook":"Game::StrategyServer::OnAllCombatDone_Tail","mode":"trace","call_id":28,"thread":9080,"depth":0,"args":[{"t":"ptr","v":"0x0ddaade0","n":"server"},{"t":"ptr","v":"0x32c8bc54","n":"results"},{"t":"i32","v":1,"n":"result_count"},{"t":"i32","v":29,"n":"turn"},{"t":"i32","v":1568,"n":"phase_counter"},{"t":"i32","v":8,"n":"players"},{"t":"i32","v":1,"n":"encounters"},{"t":"i32","v":51,"n":"node_paths"},{"t":"i32","v":51,"n":"np_permanent"},{"t":"i32","v":0,"n":"np_immortal"},{"t":"i32","v":0,"n":"np_mortal"},{"t":"i32","v":-1,"n":"np_min_life"},{"t":"i32","v":0,"n":"np_within5"},{"t":"i32","v":0,"n":"predict_nodeline_words"},{"t":"ptr","v":"0x0ddd49a0","n":"rng"},{"t":"i64","v":615,"n":"rng_words_in"},{"t":"i32","v":9,"n":"rng_left_in"}],"ret":null,"side":{"rng":{"before":{"t":"struct","v":{"left":{"t":"i32","v":9},"index":{"t":"i32","v":615},"block":{"t":"i32","v":0},"words":{"t":"i64","v":615},"block_hash":{"t":"u64","v":"1498228442844855576"}}},"after":{"t":"struct","v":{"left":{"t":"i32","v":7},"index":{"t":"i32","v":617},"block":{"t":"i32","v":0},"words":{"t":"i64","v":617},"block_hash":{"t":"u64","v":"1498228442844855576"}}}}}} +{"ts":385162902,"hook":"Game::StrategyHost::Autosave","mode":"trace","call_id":33,"thread":9080,"depth":0,"args":[{"t":"ptr","v":"0x00939f98","n":"host"},{"t":"ptr","v":"0x00cff8f0","n":"out_name"},{"t":"bool","v":false,"n":"end_turn"},{"t":"ptr","v":"0x0ddaade0","n":"server_cached"},{"t":"ptr","v":"0x03d284a8","n":"host_plus_0x54"},{"t":"bool","v":false,"n":"server_agrees"},{"t":"ptr","v":"0x0ddd49a0","n":"rng"},{"t":"i64","v":617,"n":"rng_words_in"},{"t":"i32","v":7,"n":"rng_left_in"},{"t":"list","v":[{"t":"struct","v":{"entry":{"t":"str","v":"Chance"},"ret_rva":{"t":"u32","v":3489164},"calls":{"t":"u32","v":14},"words":{"t":"u32","v":0},"no_draw_calls":{"t":"u32","v":14},"strategic":{"t":"bool","v":true}}},{"t":"struct","v":{"entry":{"t":"str","v":"NextFloat"},"ret_rva":{"t":"u32","v":1603725},"calls":{"t":"u32","v":1},"words":{"t":"u32","v":1},"no_draw_calls":{"t":"u32","v":0},"strategic":{"t":"bool","v":true}}},{"t":"struct","v":{"entry":{"t":"str","v":"NextFloat"},"ret_rva":{"t":"u32","v":4775764},"calls":{"t":"u32","v":1},"words":{"t":"u32","v":1},"no_draw_calls":{"t":"u32","v":0},"strategic":{"t":"bool","v":true}}},{"t":"struct","v":{"entry":{"t":"str","v":"NextFloat"},"ret_rva":{"t":"u32","v":5139977},"calls":{"t":"u32","v":16},"words":{"t":"u32","v":16},"no_draw_calls":{"t":"u32","v":0},"strategic":{"t":"bool","v":true}}},{"t":"struct","v":{"entry":{"t":"str","v":"Chance"},"ret_rva":{"t":"u32","v":4797483},"calls":{"t":"u32","v":8},"words":{"t":"u32","v":8},"no_draw_calls":{"t":"u32","v":0},"strategic":{"t":"bool","v":true}}},{"t":"struct","v":{"entry":{"t":"str","v":"Chance"},"ret_rva":{"t":"u32","v":4797720},"calls":{"t":"u32","v":8},"words":{"t":"u32","v":8},"no_draw_calls":{"t":"u32","v":0},"strategic":{"t":"bool","v":true}}},{"t":"struct","v":{"entry":{"t":"str","v":"NextFloat"},"ret_rva":{"t":"u32","v":1061538},"calls":{"t":"u32","v":1},"words":{"t":"u32","v":1},"no_draw_calls":{"t":"u32","v":0},"strategic":{"t":"bool","v":true}}},{"t":"struct","v":{"entry":{"t":"str","v":"NextInt"},"ret_rva":{"t":"u32","v":3746217},"calls":{"t":"u32","v":1},"words":{"t":"u32","v":1},"no_draw_calls":{"t":"u32","v":0},"strategic":{"t":"bool","v":true}}},{"t":"struct","v":{"entry":{"t":"str","v":"NextFloat"},"ret_rva":{"t":"u32","v":4328989},"calls":{"t":"u32","v":2},"words":{"t":"u32","v":2},"no_draw_calls":{"t":"u32","v":0},"strategic":{"t":"bool","v":true}}},{"t":"struct","v":{"entry":{"t":"str","v":"NextInt"},"ret_rva":{"t":"u32","v":1546517},"calls":{"t":"u32","v":3},"words":{"t":"u32","v":7},"no_draw_calls":{"t":"u32","v":0},"strategic":{"t":"bool","v":false}}},{"t":"struct","v":{"entry":{"t":"str","v":"NextFloat"},"ret_rva":{"t":"u32","v":5139977},"calls":{"t":"u32","v":1},"words":{"t":"u32","v":1},"no_draw_calls":{"t":"u32","v":0},"strategic":{"t":"bool","v":false}}},{"t":"struct","v":{"entry":{"t":"str","v":"Chance"},"ret_rva":{"t":"u32","v":1543445},"calls":{"t":"u32","v":1},"words":{"t":"u32","v":1},"no_draw_calls":{"t":"u32","v":0},"strategic":{"t":"bool","v":false}}},{"t":"struct","v":{"entry":{"t":"str","v":"NextInt"},"ret_rva":{"t":"u32","v":2743342},"calls":{"t":"u32","v":3},"words":{"t":"u32","v":3},"no_draw_calls":{"t":"u32","v":0},"strategic":{"t":"bool","v":false}}}],"n":"draw_sites"},{"t":"u32","v":38,"n":"draw_site_words"},{"t":"u32","v":52,"n":"draw_site_calls"},{"t":"u32","v":12,"n":"draw_site_words_other_rng"},{"t":"u32","v":8,"n":"draw_site_calls_other_rng"},{"t":"u32","v":0,"n":"draw_site_overflow"},{"t":"list","v":[{"t":"struct","v":{"name":{"t":"str","v":"Game::ServerSpyManager::vslot13"},"rva":{"t":"u32","v":4749232},"calls":{"t":"u32","v":1},"calls_since_launch":{"t":"u32","v":2},"installed":{"t":"bool","v":true}}},{"t":"struct","v":{"name":{"t":"str","v":"Game::ServerSpyManager::vslot14"},"rva":{"t":"u32","v":4774784},"calls":{"t":"u32","v":1},"calls_since_launch":{"t":"u32","v":2},"installed":{"t":"bool","v":true}}},{"t":"struct","v":{"name":{"t":"str","v":"Game::ServerTradeManagerImpl::vslot13"},"rva":{"t":"u32","v":4779904},"calls":{"t":"u32","v":1},"calls_since_launch":{"t":"u32","v":2},"installed":{"t":"bool","v":true}}},{"t":"struct","v":{"name":{"t":"str","v":"Game::ServerTradeManagerImpl::vslot15"},"rva":{"t":"u32","v":4377760},"calls":{"t":"u32","v":1},"calls_since_launch":{"t":"u32","v":2},"installed":{"t":"bool","v":true}}},{"t":"struct","v":{"name":{"t":"str","v":"Game::SpyManager::Slot13RngCallee"},"rva":{"t":"u32","v":4458720},"calls":{"t":"u32","v":0},"calls_since_launch":{"t":"u32","v":0},"installed":{"t":"bool","v":true}}},{"t":"struct","v":{"name":{"t":"str","v":"Game::TradeManager::Slot13RngCalleeA"},"rva":{"t":"u32","v":4328608},"calls":{"t":"u32","v":2},"calls_since_launch":{"t":"u32","v":4},"installed":{"t":"bool","v":true}}},{"t":"struct","v":{"name":{"t":"str","v":"Game::TradeManager::Slot13RngCalleeB"},"rva":{"t":"u32","v":4764736},"calls":{"t":"u32","v":0},"calls_since_launch":{"t":"u32","v":1},"installed":{"t":"bool","v":true}}},{"t":"struct","v":{"name":{"t":"str","v":"Game::ServerTradeManager::CreateRaidEncounter"},"rva":{"t":"u32","v":4798624},"calls":{"t":"u32","v":2},"calls_since_launch":{"t":"u32","v":3},"installed":{"t":"bool","v":true}}},{"t":"struct","v":{"name":{"t":"str","v":"Game::ServerTradeManager::GenerateTradeRaidEncounters"},"rva":{"t":"u32","v":4797072},"calls":{"t":"u32","v":0},"calls_since_launch":{"t":"u32","v":0},"installed":{"t":"bool","v":false}}},{"t":"struct","v":{"name":{"t":"str","v":"Game::ServerSpyManager::vslot15 [control]"},"rva":{"t":"u32","v":4751152},"calls":{"t":"u32","v":0},"calls_since_launch":{"t":"u32","v":0},"installed":{"t":"bool","v":false}}},{"t":"struct","v":{"name":{"t":"str","v":"Game::ServerTradeManagerImpl::vslot14 [control]"},"rva":{"t":"u32","v":4559056},"calls":{"t":"u32","v":0},"calls_since_launch":{"t":"u32","v":0},"installed":{"t":"bool","v":false}}},{"t":"struct","v":{"name":{"t":"str","v":"Game::EncounterDetect::Run [control]"},"rva":{"t":"u32","v":3977344},"calls":{"t":"u32","v":0},"calls_since_launch":{"t":"u32","v":0},"installed":{"t":"bool","v":false}}}],"n":"probe_entries"}],"ret":{"t":"ptr","v":"0x00cff8f0"},"side":{"rng":{"before":{"t":"struct","v":{"left":{"t":"i32","v":7},"index":{"t":"i32","v":617},"block":{"t":"i32","v":0},"words":{"t":"i64","v":617},"block_hash":{"t":"u64","v":"1498228442844855576"}}},"after":{"t":"struct","v":{"left":{"t":"i32","v":7},"index":{"t":"i32","v":617},"block":{"t":"i32","v":0},"words":{"t":"i64","v":617},"block_hash":{"t":"u64","v":"1498228442844855576"}}}}}}