Compare commits
No commits in common. "fdea0fde081fa4ca251e7b45c5bb7f3b01bb6db8" and "b6018a0f19593b5e55eb9f919554d2f03ec3dd8f" have entirely different histories.
fdea0fde08
...
b6018a0f19
26 changed files with 28 additions and 5579 deletions
|
|
@ -1,17 +1,17 @@
|
|||
# SotS RE campaign — coverage dashboard
|
||||
|
||||
Generated 2026-09-09 14:13 UTC · `sots-re` @ d4e9b58,2026-09-09 · `sots-engine` @ 52db23c,2026-09-09 (250 commits) · regenerate with `tools/dashboard.py`
|
||||
Generated 2026-09-09 13:40 UTC · `sots-re` @ c4ea347,2026-09-09 · `sots-engine` @ e7e2bd6,2026-09-09 (245 commits) · regenerate with `tools/dashboard.py`
|
||||
|
||||
> **North star:** A functional reimplementation of the engine — behavior-equivalent, NOT byte-for-byte
|
||||
|
||||
## 1. Map coverage (campaign/board.md)
|
||||
|
||||
453 targets · mapped-or-better **404/453** `[█████████░] 89%` · verified **361/453** `[████████░░] 80%`
|
||||
447 targets · mapped-or-better **399/447** `[█████████░] 89%` · verified **356/447** `[████████░░] 80%`
|
||||
|
||||
| Status | Count | % |
|
||||
|---|---:|---:|
|
||||
| verified | 361 | 80% |
|
||||
| mapped | 43 | 9% |
|
||||
| verified | 356 | 80% |
|
||||
| mapped | 43 | 10% |
|
||||
| in-progress | 5 | 1% |
|
||||
| backlog | 41 | 9% |
|
||||
| blocked | 2 | 0% |
|
||||
|
|
@ -22,16 +22,16 @@ Generated 2026-09-09 14:13 UTC · `sots-re` @ d4e9b58,2026-09-09 · `sots-engine
|
|||
| control-flow | 41 | 2 | 1 | 0 | 0 | 44 |
|
||||
| subsystems | 4 | 8 | 0 | 2 | 1 | 15 |
|
||||
| engine | 33 | 1 | 0 | 0 | 0 | 34 |
|
||||
| verify | 106 | 15 | 3 | 35 | 0 | 159 |
|
||||
| phase2 | 15 | 3 | 1 | 0 | 0 | 20 |
|
||||
| meta | 95 | 6 | 0 | 1 | 0 | 102 |
|
||||
| other | 21 | 2 | 0 | 0 | 0 | 23 |
|
||||
| verify | 105 | 15 | 3 | 35 | 0 | 158 |
|
||||
| phase2 | 13 | 3 | 1 | 0 | 0 | 17 |
|
||||
| meta | 94 | 6 | 0 | 1 | 0 | 101 |
|
||||
| other | 20 | 2 | 0 | 0 | 0 | 22 |
|
||||
|
||||
## 2. Binary understanding
|
||||
|
||||
- RTTI type descriptors: **1,924** (`Game::` 1,404, `Mars::` 194; serializable types 179)
|
||||
- Classes with recovered member layouts: **384** / 1,598 named classes `[██░░░░░░░░] 24%` — `objects/layouts.json` (serializer recovery) plus classes recovered by hand in `struct-recovery.md` + `schema-gaps-resolved.md`. Note 179 types are *serializable*; the recovery also reaches non-serializable ones, so this is not a subset of that
|
||||
- Functions: **41,411** (parsed from `01-fingerprint.md`); named/annotated in the **address contract** (`ghidra/addresses.json`, not Ghidra's full rename count): **1310**, verified **1179** `[█████████░] 90%`
|
||||
- Functions: **41,411** (parsed from `01-fingerprint.md`); named/annotated in the **address contract** (`ghidra/addresses.json`, not Ghidra's full rename count): **1298**, verified **1167** `[█████████░] 90%`
|
||||
|
||||
## 3. Data layer
|
||||
|
||||
|
|
@ -58,13 +58,13 @@ Generated 2026-09-09 14:13 UTC · `sots-re` @ d4e9b58,2026-09-09 · `sots-engine
|
|||
| `game/sim` | 4,780 | 14 | 1038 | yes | game-sim.md |
|
||||
| `mars/parse` | 875 | 12 | 277 | yes | mars-parse.md |
|
||||
| `mars/rng` | 273 | 0 | 0 | yes | mars-rng.md |
|
||||
| `mars/stream` | 6,021 | 8 | 331 | yes | mars-stream.md |
|
||||
| `mars/stream` | 5,834 | 8 | 329 | yes | mars-stream.md |
|
||||
| `mars/text` | 899 | 8 | 245 | yes | mars-text.md |
|
||||
| `mars/vfs` | 788 | 9 | 140 | yes | mars-vfs.md |
|
||||
| `shim` | 16,777 | 0 | 0 | direct (WIN32) | H-probes.md |
|
||||
| `shim/hooks` | 13,658 | 0 | 0 | direct (WIN32) | L1-predictions.md |
|
||||
| `shim` | 16,709 | 0 | 0 | direct (WIN32) | H-probes.md |
|
||||
| `shim/hooks` | 13,593 | 0 | 0 | direct (WIN32) | L1-predictions.md |
|
||||
| `shim/trace` | 2,258 | 9 | 273 | direct (WIN32) | shim-trace.md |
|
||||
| **total** | **59,834** | **122** | **4259** | | |
|
||||
| **total** | **59,514** | **122** | **4257** | | |
|
||||
|
||||
Board `engine:` rows: verified **33**, mapped 1, in flight 0 (of 34) — verified & merged `[██████████] 97%`
|
||||
|
||||
|
|
@ -133,11 +133,11 @@ Most recent open:
|
|||
|
||||
## 9. Delta since previous dashboard
|
||||
|
||||
- verified targets: 356 → 361 (+5) · mapped-or-better: 399 → 404 (+5)
|
||||
- engine LOC: 59,514 → 59,834 (+320) · test files: 122 → 122 (+0) · checks: 4,257 → 4,259 (+2)
|
||||
- addresses verified: 1,167 → 1,179 (+12) · recovered layouts: 384 → 384 (+0) · open questions: 26 → 26 (+0)
|
||||
- verified targets: 354 → 356 (+2) · mapped-or-better: 396 → 399 (+3)
|
||||
- engine LOC: 59,514 → 59,514 (+0) · test files: 122 → 122 (+0) · checks: 4,257 → 4,257 (+0)
|
||||
- addresses verified: 1,163 → 1,167 (+4) · recovered layouts: 384 → 384 (+0) · open questions: 26 → 26 (+0)
|
||||
- standalone leaves closed: 45 → 45 (+0) · leaves still diverging: 63 → 63 (+0)
|
||||
|
||||
---
|
||||
warnings: board.md line 459: unknown status 'open' for '**A replace of `ProcessResearch` is gated on `ServerPlayer::OnTechResearched`, and partly on a policy question**'; board.md: unknown types engine + gate, subsystems, tooling; mars-rng.md: no oracle total row parsed; mars-stream.md: no oracle total row parsed; mars-vfs.md: no oracle total row parsed
|
||||
<!-- dashboard-metrics {"verified": 361, "mapped_plus": 404, "targets": 453, "loc": 59834, "tests": 122, "checks": 4259, "addr_verified": 1179, "addr_total": 1310, "layouts": 384, "open_q": 26, "sa_closed": 45, "sa_left": 63} -->
|
||||
warnings: board.md: unknown types subsystems, tooling; mars-rng.md: no oracle total row parsed; mars-stream.md: no oracle total row parsed; mars-vfs.md: no oracle total row parsed
|
||||
<!-- dashboard-metrics {"verified": 356, "mapped_plus": 399, "targets": 447, "loc": 59514, "tests": 122, "checks": 4257, "addr_verified": 1167, "addr_total": 1298, "layouts": 384, "open_q": 26, "sa_closed": 45, "sa_left": 63} -->
|
||||
|
|
|
|||
|
|
@ -154,22 +154,11 @@ mode and the **same hashes**, with a count from the hook proving the path execut
|
|||
|
||||
| # | module | today | evidence for the attempt | target |
|
||||
|---|---|---|---|---|
|
||||
| 1a | `TechTree::ProcessResearch` + unlock cascade | compared | 35 calls / 3 workloads / 0 div; advance prediction held on a changed workload | **stays `compared`** (lane CR, 2026-09-09): our code displaced all 13 tech-tree leaves live, oracle missed by **16**, every one written by `OnTechResearched` — a different function. Next: the write-back |
|
||||
| 1a | `TechTree::ProcessResearch` + unlock cascade | compared | 35 calls / 3 workloads / 0 div; advance prediction held on a changed workload | **replaced** — lane CR running |
|
||||
| 1b | `ServerSystem::ComputeTotalOutput` + `GroupOutput` | compared | 24,357 calls, 0 undeclared writes — but **13 distinct states** (rule 23) | replaced, after widening the state set |
|
||||
| 1c | `ServerSystem::ProcessTurn` (colony) | compared | 36 calls 0 div; 3 owned systems, gates all zero | replaced, on a save with gate traffic |
|
||||
| 1d | `game/nav`, `game/design`, `game/combat` retreat, `mars/vfs` | modelled, **never hooked** | host-tested only | compared — one lane each |
|
||||
|
||||
**Ruling (2026-09-09, on lane CR's policy question).** Reaching `replaced` on research needs two
|
||||
event *records* whose text comes from the game's string table. That text is **game data**, not
|
||||
engine code: the engine already reads every catalogue, tech name and design from the user's own
|
||||
install through `$SOTS_DATA_DIR` / the VFS, and a string table is no different. So the answer is
|
||||
**not** "call the game's `PostEvent` and take a QUALIFIED caveat" — it is **load the string table
|
||||
through the same VFS path everything else uses** and construct the record clean. We ship no
|
||||
strings; the user's copy supplies them. That is the same clean-room posture as every other data
|
||||
dependency, and it turns the last research residual into ordinary engine work rather than a
|
||||
policy exception. Track 1a, next lane: `OnTechResearched` write-back (~90 tech-effect fields) +
|
||||
`ObservedTech` element + the two event records via the VFS string table.
|
||||
|
||||
### Track 2 — Rung B worklist, ranked against a real rich turn (lane CV, residual 0)
|
||||
|
||||
| leaves | subsystem | note |
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -249,305 +249,3 @@ OK; `tools/check_shim_configs.py` OK with 27 registered hooks and all four CR co
|
|||
## 4. Results
|
||||
|
||||
*(added after the runs; nothing above this line is edited)*
|
||||
|
||||
### 4.0 The five runs, in order
|
||||
|
||||
All five on **VM145**, held by this lane, each a **fresh process**, `SavedGames` reset to exactly
|
||||
`turn3-state.sav` before every launch, `C:\SOTS\shimdist-cr\binkw32.dll`
|
||||
(25,274,723 B, sha256 `d2ad56b32c1b5f6b…`, `BUILD_ID cr-618ccb1-20260909T131556Z`, exports 66/66
|
||||
identical to the real `binkw32.dll`), one config per run and nothing else changed. Every screen —
|
||||
main menu, Load-Game chooser, the one-row file list, the **lobby**, the loaded map at "Turn 3", the
|
||||
post-turn map at "Turn 4" — was verified from a live `qm monitor` screendump before the next click.
|
||||
No run was driven by sleeping.
|
||||
|
||||
| run | config | mode | `research.replace_cascade` | `(Autosave EndTurn).sav` | `(Autosave).sav` |
|
||||
|---|---|---|---|---|---|
|
||||
| **C1** | `croff` | `hooks=off` | – | 67,212 `e00eed0c…` | 67,811 `79df5047…` |
|
||||
| **C2** | `croff` | `hooks=off` | – | 67,212 **`e00eed0c…`** | 67,811 **`79df5047…`** |
|
||||
| **N** | `crcompare` | compare | off | 67,212 **`e00eed0c…`** | 67,811 **`79df5047…`** |
|
||||
| **R0** | `crreplace0` | **replace** | off | 67,212 `e00eed0c…` | 67,511 **`6b51db99…`** |
|
||||
| **R1** | `crreplace1` | **replace** | **on** | 67,212 `e00eed0c…` | 67,537 **`8a4309ee…`** |
|
||||
|
||||
`(Autosave EndTurn).sav` is the *pre*-turn resave and is identical in all five runs, as it must be —
|
||||
nothing has run yet when it is written. The verdict is carried entirely by `(Autosave).sav`.
|
||||
|
||||
### 4.1 P0 held: the oracle
|
||||
|
||||
**C1 and C2 agree byte-for-byte in two fresh processes.** The pair, in the standing
|
||||
`certified-pairs.md` format:
|
||||
|
||||
| input | procedure | route | `(Autosave EndTurn)` | `(Autosave)` | processes | evidence |
|
||||
|---|---|---|---|---|---:|---|
|
||||
| `turn3-state.sav` `978041ac…` | one End Turn | **load** | `e00eed0c…` | `79df5047…` | **3** | lane CR ×2 `hooks=off`, ×1 compare-instrumented |
|
||||
|
||||
**Masks that must be on the line.** Measured, not assumed —
|
||||
`state_checksum.py turn3-state.sav <(Autosave EndTurn)>` gives **exactly 5 leaves**:
|
||||
`/Summary/Checksum` and `Player.Status 4 → 0` on each of the four live players (16 `re`,
|
||||
32 `Fane Lao`, 496 and 512 `Singularity`). **There is no `/CD[1]/NPrvVa` term on this state** —
|
||||
`CD[1]`'s diplomacy block is early-game and the leaf does not move — so the `--mask resave` rule
|
||||
holds here in the form the docs originally stated, and the lane BQ exception does not apply.
|
||||
|
||||
**Exposure facts next to the hashes** (certified-pairs standing rule 4): §1.3's table — no player
|
||||
with an AI client enters the turn with `ResTNm == ''`; `NumDes` does not move; the two ships that
|
||||
complete join existing fleets; the four factions at 528–576 carry the empty-`ResTNm` signature
|
||||
inertly (`Status 0`, no client). The turn does create fleets (`Flt[50]`, `Flt[1808]`) and retire one
|
||||
(`Flt[1776]`) — that is a fleet-assignment shape, and it agreed anyway. **Which is the point of
|
||||
rule 26(c)'s retraction: the screen said "likely fine" and only the two-process control decided it.**
|
||||
|
||||
### 4.2 P3 held: the instrument is neutral, and it counts the completion itself
|
||||
|
||||
Run **N** reproduced the control's two hashes exactly, so rule 19 is satisfied on *this* save and
|
||||
*this* route and everything below is read from runs that passed their own check.
|
||||
`tracecmp verify/traces/cr-N.jsonl.gz`: **3 calls, 3 compared, 0 diverged, exit 0**, coverage verdict
|
||||
`partial`, 8 unmodelled notes — and the undeclared-write set is **exactly the six spans predicted**:
|
||||
|
||||
```
|
||||
player+0x10c:3 player+0x110:3 player+0x114:3 player+0x124:3 player+0x294:4 tree_header+0x20:1
|
||||
```
|
||||
|
||||
The hook's own per-call line, which is the instrument saying a completion fired rather than the save
|
||||
being asked to imply it:
|
||||
|
||||
```
|
||||
research: mode=compare steps=1 completions=1 overbudget=1166 cascade_possible=1 ok=1
|
||||
cascade_completions=1 unlocked=3 otch_appends=1 roll_draws=0 failures=0 depth=0
|
||||
research: mode=compare steps=1 completions=0 … (×2, all zero)
|
||||
```
|
||||
|
||||
**A correction to the campaign's read of the detour count, and it goes the other way from the
|
||||
brief's warning.** My config names all **27** registered template hooks and
|
||||
`check_shim_configs.py` passes it as `# exhaustive` — and the shim still installed **six** detours,
|
||||
not one:
|
||||
|
||||
| detour | source | named by a `hook.` key? |
|
||||
|---|---|---|
|
||||
| `Mars::Application::Initialize` | the M0 asm stub, installed unconditionally whenever `hooks != off` | **no** |
|
||||
| `Game::TechTree::ProcessResearch` | the one template hook | yes |
|
||||
| `StrategyClient::EndTurn`, `StrategyServer::BeginProcessTurn`, `StrategyServer::ProcessTurn`, `DemoApp::OnTick` | the **FPU-force module**, which installs four *sampling* detours by default (`fpu: module init … force=off value=0x0000 sample_ticks=on`, `sample_turn=on`) | **no** |
|
||||
|
||||
`Shim::SelfTest::Fill` additionally emits one `trace` record at startup; it is an in-shim self-test,
|
||||
not a detour on the game. So **`# exhaustive` is exhaustive over the template-hook set only**, and
|
||||
`tools/check_shim_configs.py` cannot see the other five. It was the *neutrality check* (N identical
|
||||
to C1/C2), not the config check, that made this run safe — which is worth saying plainly, because a
|
||||
lane reading "exhaustive, therefore one detour" would be wrong by five.
|
||||
|
||||
For the record, `fpu_cw = 0x027f` (53-bit, round-to-nearest) in every CR run.
|
||||
|
||||
### 4.3 P1 and P2 held exactly, on the LOAD route
|
||||
|
||||
The load route reproduced the continuation's turn-4 call in every particular — allocations, the
|
||||
completion, the unlock set, the arithmetic. From `cr-N.jsonl.gz` (compare) and confirmed identically
|
||||
in `cr-R1.jsonl.gz` (replace):
|
||||
|
||||
| call | owner | species | alloc | what moved |
|
||||
|---|---|---|---|---|
|
||||
| 1 | `Player[32 "Fane Lao"]` | 2 | `{144, 2898}` | the completion (below) |
|
||||
| 2 | `Player[496 "Singularity"]` | 0 | `{90, 0}` | **nothing at all** |
|
||||
| 3 | `Player[512 "Singularity"]` | 2 | `{9, 0}` | **nothing at all** |
|
||||
|
||||
Call 1, node **144 `IND_Waldo`**: `state 3 → 4`, `progress 5768 → 7500`, `turn_researched −1 → 4`,
|
||||
`order −1 → 22`; `overbudget 0 → 1166`; three nodes unlocked —
|
||||
**132 `IND_OrbFound` @ 10000**, **136 `IND_RefCoat` @ 16000**, **142 `IND_TrkStl` @ 8000**, each
|
||||
`state 0 → 2`, `cost_rp INT_MAX → …`, `turn_available −1 → 4`; `events.next_id 5 → 7`;
|
||||
`observed_techs 440 → 484 bytes`.
|
||||
|
||||
P2's hand arithmetic is confirmed to the unit: `cost 5000`, `lo 2500`, `hi 7500`,
|
||||
`spent = min(2898, 1732) = 1732`, `progress = 7500` **exactly on the ceiling**,
|
||||
`overbudget = 2898 − 1732 = 1166`; `progress < hi` false so **no draw**; `ratio = 1.5`, not below
|
||||
`0.800000011920929`, so **`flag` unchanged**. The `rng` region **did not move on any of the three
|
||||
calls** in any run.
|
||||
|
||||
That last fact is a coverage hole, not a success — see §4.6.
|
||||
|
||||
### 4.4 P4 and P5 held: replace diverges, and the cascade closes exactly eleven leaves
|
||||
|
||||
`state_checksum.py cr-oracle-autosave.sav <replace autosave>`:
|
||||
|
||||
| run | diverging leaves | file size |
|
||||
|---|---:|---|
|
||||
| **R0** — replace, cascade **off** (the shipped behaviour) | **27** | 67,511 B |
|
||||
| **R1** — replace, cascade **on** | **16** | 67,537 B |
|
||||
| (the turn itself, `turn3-state` → oracle, for scale) | 128 | – |
|
||||
|
||||
**The eleven leaves the cascade closes — R0 has them, R1 does not.** All eleven are `TechTree`:
|
||||
|
||||
```
|
||||
Player[32]/TechTree/St[94] TResCost[94] TUnlck[94] (node 132 IND_OrbFound, 10000)
|
||||
Player[32]/TechTree/St[98] TResCost[98] TUnlck[98] (node 136 IND_RefCoat, 16000)
|
||||
Player[32]/TechTree/St[104] TResCost[104] TUnlck[104] (node 142 IND_TrkStl, 8000)
|
||||
Player[32]/TechTree/TAcq[106] TiAcq[106] (node 144, turn 4 / order 22)
|
||||
```
|
||||
|
||||
The tree is serialised as parallel arrays indexed by **tree slot**, not tech id — slots 94/98/104/106
|
||||
are tech ids 132/136/142/144 — and the pass's own two words, `St[106] 3 → 4` and
|
||||
`TResDone[106] 5768 → 7500`, are correct in **both** replace runs because
|
||||
`ProcessResearchTurn` writes them without the cascade. So of the **13 tech-tree leaves this turn
|
||||
moves, our code produced all 13 in live memory with the original's `ProcessResearch` never
|
||||
executing** — 2 from the pass, 11 from `SetResearched`.
|
||||
|
||||
**One prediction I cannot test and must retract as written.** P4 item 2 said the completion-order
|
||||
counter would be "left at 22" in R0. `TechTree+0x20` **is not a save leaf** — the counter's value
|
||||
surfaces only through the per-node `TiAcq` stamp — so the oracle cannot see it either way. What is
|
||||
observable is the trace: R1's only guard hit is `tree_header+0x20:1` (ours writing 22 → 23, the same
|
||||
byte the original moves in compare mode) and R0 has **0 undeclared writes in 0 calls**. The counter
|
||||
matters for the *next* completion, not for this save.
|
||||
|
||||
### 4.5 P6 held: the residual is `ServerPlayer::OnTechResearched`, entirely
|
||||
|
||||
R1's **16** leaves, every one of them named, with nothing left over:
|
||||
|
||||
| leaf | what it is | modelled by `ours`? |
|
||||
|---|---|---|
|
||||
| `Player[32]/OutMod` `1.25 → 1.1` | a tech effect | no — B2's milestone |
|
||||
| `Player[32]/ConMod[0..2]` `0.9 → 1.0` (×3) | tech effects | no — B2's milestone |
|
||||
| `Player[32]/Events/EvNxID` `7 → 5` | the two events not posted | decision modelled, **write is compare-only** |
|
||||
| `…/Events/.[EvTurn=4]/Events/.[EvEID=5]`, `.[EvEID=6]` `only-in-A` | the two event records | text comes from the game's string table |
|
||||
| `…/Events/.[EvTurn=4]/Events/.[0]` `3 → 1` | that turn's event count | ditto |
|
||||
| `Player[32]/otch/.[11]` `only-in-A`, `otch/.[0]` `11 → 10` | the `ObservedTech` element | append **decided** (`otch_appends=1`), element not constructed |
|
||||
| `Player[32]/ResTNm` `'' → 'IND_Waldo'` | `ResT` never cleared | inside the callback |
|
||||
| `Player[32]/BnkPr`, `BnkEl` | bankruptcy projection | **downstream of `OutMod`** |
|
||||
| `Sys[288 "Ke'Dolarra"]/RepCur`, `RepMax` `421640 → 371040` | repair capacity | **downstream of `ConMod`** |
|
||||
| `/Summary/Checksum` | derived | derived |
|
||||
|
||||
So the residual decomposes into **5 primary player fields** (`OutMod`, `ConMod[0..2]`, `ResTNm`),
|
||||
**1 `ObservedTech` element**, **2 event records + their id counter**, and **5 derived leaves** that
|
||||
follow from those. Every single one is written by `ServerPlayer::OnTechResearched`, none of them by
|
||||
`TechTree::ProcessResearch` or by `SetResearched`.
|
||||
|
||||
That also closes the loop with §4.2's guard: the four `player` spans the compare reported as
|
||||
undeclared (`+0x10c`, `+0x110`, `+0x114`, `+0x124`, all three bytes wide — float writes whose top
|
||||
byte did not change) plus `+0x294` (`ResT`, four bytes) are **five** writes, and the save shows
|
||||
**five** primary player fields. The guard was reporting exactly what the oracle later billed us for.
|
||||
|
||||
**The input class that breaks it is a completion, and only a completion.** Both replace runs are
|
||||
byte-perfect on the two null calls and on every other leaf of the 128 the turn moves. A replace run
|
||||
over a turn where research does not complete would be byte-identical — and would prove nothing
|
||||
(rule 1), which is why this lane refused to run it on `ref-turn2`.
|
||||
|
||||
### 4.6 Coverage, reported as loudly as the result (rules 15 and 23)
|
||||
|
||||
* **1 completion. 1 distinct tech (144 `IND_Waldo`). 3 unlocked nodes. 3 calls.**
|
||||
* **2 of the 3 calls allocate zero points and write nothing at all**, in any mode. Their entire
|
||||
contribution to "3 calls, 0 diverged" is that two null calls stayed null.
|
||||
* **1 of 4 tech trees is exercised.** Player 16's tree is never processed (`ResTNm == ''`); players
|
||||
496 and 512 are the null calls.
|
||||
* **The RNG region did not move on any call in any run.** The spend cap bound exactly, so the
|
||||
odds/roll branch was skipped, and `roll_pending_in` was false on the completing call, so
|
||||
`RollResearchEvent` drew nothing (`roll_draws=0`). **`region:rng` — the single strongest check in
|
||||
this hook's compare — compared "unchanged against unchanged" on this workload and established
|
||||
nothing.** The generator parity evidence for this module is entirely lane U's and lane V's,
|
||||
on other turns.
|
||||
* **Branches that did not execute here:** the Zuul double roll (species 2, not 5); the
|
||||
completed-early flag (`ratio 1.5`); the over-budget notification (`flag` already 2 from turn 3);
|
||||
`RollResearchEvent`'s draw and, behind it, the plague / AI-rebellion paths; `SetResearched`'s
|
||||
zero-cost recursion; the `def+0xb0` `NoAutoAvailable` skip; an empty prerequisite group; a
|
||||
re-observed tech (the dedup's negative case); and the decay sweep, which ran over every node and
|
||||
**changed nothing** because no other `Available` node had non-zero progress.
|
||||
* **The event model is count-only by construction** and stayed compare-only in replace mode by
|
||||
design; the two missing records are two of the sixteen residual leaves.
|
||||
* **`TechTree::Cost` is the original's.** `ours` calls the game's read-only `Cost` for every cost it
|
||||
needs, in both modes. The effective-cost formula is **not** displaced, and any claim about this
|
||||
module inherits that dependency.
|
||||
|
||||
### 4.7 Verdict
|
||||
|
||||
**No. `game/sim/research` does not move from `compared` to `replaced`.**
|
||||
|
||||
The bar is "our code ran instead of the original's **and a byte-level oracle held afterwards**". Our
|
||||
code did run instead — `mode=replace`, `completions=1`, `unlocked=3`, the original's
|
||||
`ProcessResearch` never executed, and the game finished the turn and wrote a save. The oracle did
|
||||
**not** hold: 16 leaves in the best configuration. There is no qualified reading that rescues it,
|
||||
because the failure is not a rounding residual — it is a set of writes nobody has implemented.
|
||||
|
||||
What the lane did establish, and it is worth more than the rung would have been:
|
||||
|
||||
1. **The research pass and the entire `SetResearched` cascade are displaceable and were displaced.**
|
||||
All 13 tech-tree leaves the turn moves were produced by our code in live game memory, on a turn
|
||||
with a real completion and a real three-node unlock cascade — which is a strictly stronger
|
||||
statement than the 35 compared calls the board already carried, because in a compare the
|
||||
original's code still did the work.
|
||||
2. **The blocking boundary is named and measured, not guessed:** `ServerPlayer::OnTechResearched`,
|
||||
5 player fields + 1 `ObservedTech` element + 2 events, and 5 derived leaves behind them.
|
||||
`ProcessResearch` **cannot** reach `replaced` on any workload containing a completion until
|
||||
`OnTechResearched` is displaced — and that is B2's milestone and its own `compared` board row,
|
||||
not a defect in the research model.
|
||||
3. **A new certified pair** on a turn that exercises the completion path, which the campaign did not
|
||||
have: `ref-turn2` + one End Turn is a *quiet* turn for research, and every oracle the module had
|
||||
been checked against was that one.
|
||||
|
||||
The cheapest route to the rung, now that the boundary is priced: implement the ~90-field
|
||||
`ApplyTechEffect` write-back live (B2 already has `game/effects/tech_effects` host-tested), construct
|
||||
the `ObservedTech` element, and decide what to do about the two event records — whose *text* comes
|
||||
from the game's string table and therefore cannot be produced clean-room at all. **The event text is
|
||||
a hard stop for a byte-identical oracle on any completion turn**, and that should be settled as a
|
||||
policy question (call the game's `PostEvent`, and accept the `ComputeBudget`-shaped QUALIFIED
|
||||
caveat) before anyone spends another lane on it.
|
||||
|
||||
---
|
||||
|
||||
## 5. Proposed board rows
|
||||
|
||||
**I have not edited `campaign/board.md`.** I *have* added the certified pair to
|
||||
`verify/results/saves/certified-pairs.md`, which the brief pointed at as the standing format and
|
||||
whose four standing rules for adding a row are all satisfied (two fresh `hooks=off` processes; the
|
||||
control run before anything was read from an instrumented run; not an extension of an existing pair
|
||||
but its own agreement; exposure facts recorded beside the hashes).
|
||||
|
||||
### 5.1 `tools/displacement.py` — the rung does NOT move
|
||||
|
||||
The verdict is **no**, so `"compared"` stays. What I do propose is replacing the evidence and caveat
|
||||
strings, which currently understate what is known and do not name the gate:
|
||||
|
||||
```python
|
||||
("TechTree::ProcessResearch + unlock cascade", "compared",
|
||||
"35 calls across 3 workloads, 0 divergences, tracecmp exit 0; advance prediction held on a "
|
||||
"changed workload (unlock costs no earlier report contained); REPLACE ATTEMPTED live (lane "
|
||||
"CR): ours ran instead of the original on a real completion and produced all 13 tech-tree "
|
||||
"leaves the turn moves, but the save oracle missed by 16 leaves",
|
||||
"compare only. The replace attempt failed on ServerPlayer::OnTechResearched, not on the "
|
||||
"research model: 5 player tech-effect fields, 1 ObservedTech element and 2 event records, "
|
||||
"plus 5 derived leaves. Gated on B2. Thin: 1 completion, 1 tech, 2 of 3 calls allocate zero "
|
||||
"points, and the RNG region did not move at all on the replace workload"),
|
||||
```
|
||||
|
||||
### 5.2 Board rows to add
|
||||
|
||||
| row | class | status | conf | cov | date | evidence |
|
||||
|---|---|---|---|---|---|---|
|
||||
| **`ProcessResearch` replace: our code ran instead of the original's, and the oracle missed by 16 leaves — all of them `OnTechResearched`'s** | phase2 | verified | high | 95% | 2026-09-09 | **Lane CR, VM145**, `findings/subsystems/research-replace.md`. Predictions committed before the build (`sots-re` 4b3cc82); engine `wip/cr` 618ccb1 adds `research.replace_cascade=on\|off` (default off) so the shipped and extended behaviours differ by **a config line, not a binary**. New certified pair `turn3-state.sav` → one End Turn, **load** route, `e00eed0c…`/`79df5047…`, 2 `hooks=off` processes + 1 compare. Compare run **3/3/0 exit 0** and byte-identical to the control (rule 19 satisfied), undeclared writes exactly the 6 predicted spans. **Replace, cascade on: 16 diverging leaves; cascade off: 27.** The 11-leaf delta is the whole `SetResearched` cascade and it is **ours**; with the pass's own 2 words that is **13 of 13 tech-tree leaves the turn moves, produced live by our code**. The 16 residual leaves are `OutMod`, `ConMod[0..2]`, `ResTNm`, one `ObservedTech` element, two event records + `EvNxID`, and 5 derived. **Verdict: stays `compared`.** |
|
||||
| **`ref-turn2` + one End Turn does NOT exercise a research completion** | verify | verified | high | 100% | 2026-09-09 | Lane CR. The campaign's most-reproduced oracle is a **quiet turn for the completion path**: `unlock-b3-t1.md` reports `0 undeclared write(s) in 0 call(s)` and `unlock-shim.log`'s first three lines read `completions=0`. It *is* a real workload for the pass (one RNG word, `flag 1 → 2`, one over-budget event) — but a replace-mode oracle taken there would be rule 1's green verdict on a hook comparing nothing. The completing turn is the **next** one, from `turn3-state.sav`. |
|
||||
| **`# exhaustive` is exhaustive over the 27 template hooks only — six detours are installed, not one** | phase2 | verified | high | 100% | 2026-09-09 | Lane CR. A config naming all 27 registered hooks `off` except one, passing `tools/check_shim_configs.py`, still installs **6** detours: the M0 `Application::Initialize` asm stub (unconditional whenever `hooks != off`) and the **FPU-force module's four sampling detours** (`force=off value=0x0000 sample_ticks=on sample_turn=on`, on by default). `check_shim_configs.py` cannot see either group — no `hook.` key names them. What made lane CR's runs safe was the **neutrality check** (compare run byte-identical to two `hooks=off` controls), not the config check. A lane reading "exhaustive, therefore one detour" is wrong by five. |
|
||||
| **A replace of `ProcessResearch` is gated on `ServerPlayer::OnTechResearched`, and partly on a policy question** | phase2 | open | high | – | 2026-09-09 | Lane CR. To reach `replaced`, three things are needed: the ~90-field tech-effect write-back applied live (B2 has `game/effects/tech_effects` host-tested), the `ObservedTech` element constructed (`ours` already decides the append), and the two research event **records** written. The third is not an implementation gap: their `EvDsc`/`EvMsg` text comes from the game's string table, which the engine must not carry, so a byte-identical oracle on any completion turn requires calling the game's own `PostEvent` and accepting a `ComputeBudget`-shaped **QUALIFIED** `replaced`. Settle that before spending a lane. |
|
||||
|
||||
### 5.3 Artefacts
|
||||
|
||||
| what | where |
|
||||
|---|---|
|
||||
| predictions commit (before the build) | `sots-re` `4b3cc82` |
|
||||
| engine change | `sots-engine` worktree `wip/cr`, `618ccb1` — `research.replace_cascade`, a mode-independent completion counter, four `shim.cfg.cr*` configs |
|
||||
| oracle + replace saves | `verify/results/saves/cr/cr-{oracle-endturn,oracle-autosave,replace0-autosave,replace1-autosave}.sav` |
|
||||
| traces | `verify/traces/cr-{N,R0,R1}.jsonl.gz` |
|
||||
| `tracecmp` reports | `verify/results/compare/cr-{compare,replace0,replace1}.{md,json}` |
|
||||
| shim logs (the per-call counters) | `verify/results/shim/cr/cr-{N,R0,R1}.log` |
|
||||
| certified pair | `verify/results/saves/certified-pairs.md`, row 4 |
|
||||
|
||||
No `ghidra/addresses.d/cr.json`: this lane read no new address. No game data, save, disassembly or
|
||||
`FUN_xxxxxxxx` name reached `sots-engine`; `tools/clean_room_check.sh` OK.
|
||||
|
||||
### 5.4 VM145 released
|
||||
|
||||
Held for this lane only; **VM140 untouched**. Restored and verified byte-for-byte to as-found:
|
||||
|
||||
```
|
||||
binkw32.dll 15,527,327 B 903527F4A698EEA9FBE25F3A6236657C7D8348F994EEF394696F187E5E554B97 (= shimdist-recap)
|
||||
shim.cfg 0AE410CC72FE155837D711C78543E14B1F5743310CD023298EB1E5BBD5457E71 (= shimdist-recap\shim.cfg.recaptrace)
|
||||
SavedGames the same 9 files, every size and sha256 identical to the as-found survey
|
||||
game not running (as found)
|
||||
```
|
||||
|
||||
Left behind: `C:\SOTS\shimdist-cr\`, `C:\SOTS\ui\cr\` (the input save, the four run outputs and the
|
||||
restore set) and `C:\SOTS\ui\cr{deploy,click,grab,snap,restore,find}.ps1`. `click_helper.ps1` is
|
||||
unmodified. **One thing not restored:** my deploy helper *deletes* `C:\SOTS\shim.log` rather than
|
||||
rotating it to `.prev` the way lane BQ's does, so whatever log was there when I took the guest is
|
||||
gone. Logs are not simulation state and no measurement depends on it, but the next lane should
|
||||
rotate rather than delete.
|
||||
|
|
|
|||
|
|
@ -1,248 +0,0 @@
|
|||
# `T34 RecordObservedDesigns` — the phase, its gate, and what it closes
|
||||
|
||||
- **Type:** subsystem / engine implementation
|
||||
- **Owner / date:** lane DT · 2026-09-09 · **HOST ONLY**. No VM was touched; VM140/141/145/146
|
||||
were not approached, not pinged and not logged into. The corpus was read, never written.
|
||||
- **Trigger:** `campaign/backlog.md` §2/§3 Track 2, and
|
||||
`findings/subsystems/rung-b-rich-turn.md` §5 rank 4 — lane CV's ranked worklist names
|
||||
`T34 RecordObservedDesigns` (stub) as "79 leaves, no upstream dependency", the largest
|
||||
independently closable item measured against a rich turn.
|
||||
- **Consumes:** CV's measurement (`verify/results/standalone/cv/*`), lane BR's deep block
|
||||
`verify/results/turncommands/br2-turn27-deep.tcb`, lane X/S's `observedtech-append.md`
|
||||
(the sibling `ObservedTech` record and its 0x2c element), lane PL's `players-residual.md`
|
||||
§M3, lane T's `combat-done-tail.md` phase table.
|
||||
- **Touches:** `sots-engine`: `src/game/sim/observed.{h,cpp}` (new),
|
||||
`src/app/observed_phase.{h,cpp}` (new), `src/app/turn.cpp`, `src/app/phase_catalog.cpp`,
|
||||
`tests/game_sim/test_observed.cpp` (new), two `CMakeLists.txt`.
|
||||
`sots-re`: this file, `ghidra/addresses.d/dt.json`, `verify/results/standalone/dt/*`.
|
||||
**`src/mars/stream/` was not touched** — that is lane DW's file set this round.
|
||||
|
||||
---
|
||||
|
||||
## 1. The prediction, written and committed before the engine was built (rule 2)
|
||||
|
||||
This is a *computed* prediction, not a guess: the mechanism below was read out of the
|
||||
instruction stream first, then simulated in Python against the save corpus, and the numbers
|
||||
below are that simulation's output. What the build then tests is whether the C++ in
|
||||
`sots_turn` — reading the save through the engine's own typed shapes, in the engine's own
|
||||
iteration order — reproduces the simulation. Any disagreement is an engine/order defect, and
|
||||
that is exactly the thing this prediction is for.
|
||||
|
||||
| # | prediction | why |
|
||||
|---|---|---|
|
||||
| **P1** | On the rich turn the **`odes` sub-group closes 34 of its 55 leaves and regresses 0**; 21 remain. | The mechanism is fully determined by the wire (§2). The 21 that remain are the shadow of two designs — 1826 and 1522 — whose **first ships are built during turn 27→28**; this engine builds no ship, so it cannot observe them, and their absence changes which entries the 20-per-owner cap evicts. |
|
||||
| **P2** | The **`otch` + `owep` sub-group (24 leaves) closes 0 and regresses 0.** | Not implemented: the design→tech and design→weapon lists the phase feeds to `RecordObservedTech`/`RecordObservedWeapon` are built by three `std::set` builders in the original that are not decoded, and the wire's own `DOpts` list covers only 13 of the 18 tech names this turn touches (§4). Named as a dependency, not attempted. |
|
||||
| **P3** | Rich-turn total: **1092 → 1058**. | P1 + P2, with nothing else moving. |
|
||||
| **P4** | On the **canonical pair the phase closes 1 leaf and regresses 0** (`Player[32]/odes/.[1]/otnL: 2 → 3`). | The whole canonical-pair `odes` residual is that one stamp; the simulation reproduces it exactly, including the eight players whose lists must stay empty. |
|
||||
| **P5** | The **NPC guard is load-bearing and its absence is a 4-leaf regression on the canonical pair**, not on the rich turn. | Without it, player 528 ("Alien Menace", NPC) gains four `odes` entries the target does not have. This is the one place the two pairs disagree about which rule is needed, and it is why both pairs are run. |
|
||||
|
||||
**Falsifiers, each with its symptom.**
|
||||
|
||||
1. *The engine's fleet/ship iteration order is not the save's order.* Symptom: the surviving
|
||||
`odid` sequence is a different permutation and the rich-turn residual is **worse than 21**.
|
||||
2. *A player observes ships it does not own.* The gate in the original is a two-bit-per-player
|
||||
field on the ship that is **not on the wire**; this implementation stands in for it with
|
||||
ownership (§3.3). Symptom: entries appear for foreign designs — a regression, on either pair.
|
||||
3. *`sim.frame` is not the post-increment turn at tail time.* Symptom: every `otnL` is off by
|
||||
one and the residual **grows** rather than shrinks.
|
||||
4. *The cap is not 20, or is not per design-owner.* Symptom: the list length is wrong, which
|
||||
is a `LEN` leaf plus four per extra element.
|
||||
|
||||
---
|
||||
|
||||
## 2. What the phase is — read from the instruction stream
|
||||
|
||||
**`T34` is `0x007c2350`**, 222 bytes, called from `OnAllCombatDone_Tail` `0x007d92a0` at
|
||||
`0x007d98aa` (lane T already had it as tail phase 34: "record observed designs into
|
||||
`ServerPlayer+0x254/+0x258`"). Its two other callers are `BuildTurnEvents` `0x007db780` and
|
||||
`LoadGame` `0x007dd530`.
|
||||
|
||||
### 2.1 The phase body — a triple loop with one gate
|
||||
|
||||
```
|
||||
for pi in 0 .. |S->Players|: ; S+0x54 / S+0x58
|
||||
p = S->Players[pi]
|
||||
for fi in 0 .. |S->Fleets|: ; S+0x64 / S+0x68
|
||||
f = S->Fleets[fi]
|
||||
for si in 0 .. |f->ships|: ; f+0xa4 / f+0xa8
|
||||
sh = f->ships[si]
|
||||
if (p->PlyrIdx(+0x28) >= 15) continue ; 0x007c23bf cmp eax,0xf ; jge
|
||||
cl = 2 * p->PlyrIdx
|
||||
if (((sh->+0x54 >> cl) & 3) != 3) continue ; 0x007c23ce and eax,[edx+0x54]
|
||||
RecordObservedDesign(S, p, sh->design(+0x14)) ; 0x007c23e2
|
||||
```
|
||||
|
||||
Two things to carry away. The **outer** loop is players and the **inner** two are the whole
|
||||
fleet list, so the phase is O(players × ships) and every player is offered every ship in the
|
||||
game. And the gate is a **two-bit-per-player field at `Ship+0x54`** — index `2*PlyrIdx`, both
|
||||
bits required. `Ship+0x54` is **not serialised**: the ship's on-disk field list runs
|
||||
`… +0x4c Dep, +0x4d Atq, +0x5c LCT, +0x60 tsd …` with `0x54` and `0x58` absent
|
||||
(`objects/layouts.json`, `Game::StarShip`). The cap at 15 players is the same cap
|
||||
`src/game/sim/visibility.h` already records for the runtime companion of the system masks.
|
||||
|
||||
### 2.2 `RecordObservedDesign` — `0x007be340`, `ret 8`
|
||||
|
||||
`this` is the `StrategyServer`; arg 0 is the observing `ServerPlayer*`, arg 1 the `Design*`.
|
||||
|
||||
```
|
||||
if (!player || !design) return;
|
||||
owner = design->+0x130 ; the design's owning ServerPlayer
|
||||
if (owner->+0xfb != 0 && owner->+0xfc == 0) return; ; 0x007be389 / 0x007be392
|
||||
if (!Design::vt-ish 0x0080baf0(design)) return; ; 0x007be3a1
|
||||
if (Design::HasFlag(design, 0x400, 0)) return; ; 0x007be3b7 -> 0x00813ab0
|
||||
|
||||
; --- dedup, on odid ALONE (not on the (odid, opid) pair) ---
|
||||
for (e = player->odes._Myfirst; e != _Mylast; e += 0x10) ; *** stride 0x10 = 16 ***
|
||||
if (e->+0x8 == design->id) break; ; +0x8 is `odid`
|
||||
|
||||
if (e == _Mylast) { ; APPEND 0x007be3f5
|
||||
push_back(ObservedDesign{}); ; ctor 0x0080da30, push_back 0x00799d80
|
||||
back->+0x4 = S->turn(+0xc); ; otnF (16-bit)
|
||||
back->+0x6 = S->turn; ; otnL (16-bit)
|
||||
back->+0x8 = design->+0xa0->+0x4; ; odid
|
||||
back->+0xc = owner->+0x4; ; opid
|
||||
if (owner != player) <notify list at S->+0x284 + 0x10*player->PlyrIdx>
|
||||
} else { ; MOVE-TO-BACK 0x007be618
|
||||
tmp = *e; ; otnF/otnL/odid/opid copied out
|
||||
odes.erase(e); ; 0x00795c40
|
||||
odes.push_back(tmp); ; 0x00799d80
|
||||
}
|
||||
back->+0x6 = S->turn; ; otnL, common to both paths
|
||||
|
||||
; --- the cap: 20 entries per DESIGN-OWNER, counted from the BACK 0x007be67f ---
|
||||
kept = 0
|
||||
for (i = count-1; i >= 0; --i)
|
||||
if (odes[i].opid == owner->+0x4) {
|
||||
if (kept >= 0x14) { <notify if odes[i].opid != player id>; erase odes[i]; }
|
||||
else ++kept;
|
||||
}
|
||||
```
|
||||
|
||||
`sizeof(Game::ObservedDesign) = 0x10`, and the element is
|
||||
`{vptr @+0x0, uint16 otnF @+0x4, uint16 otnL @+0x6, int odid @+0x8, int opid @+0xc}` — the
|
||||
wire record `otnF otnL odid opid` exactly, with the vptr accounting for the difference between
|
||||
12 on disk and 16 in memory. (Compare its sibling `Game::ObservedTech` at `0x2c`, whose extra
|
||||
0x1c is the embedded tech-name `std::string` — `observedtech-append.md` §4.)
|
||||
|
||||
**Three facts here are the whole finding, and none of them is guessable from the wire:**
|
||||
|
||||
- **the dedup key is `odid` alone.** A design id is globally unique in this game, so this only
|
||||
matters if two owners could ever share one — but it is what the code does, and modelling it
|
||||
as a `(odid, opid)` pair would be a different program.
|
||||
- **re-observation is `erase` + `push_back`, not an in-place update.** The list is therefore
|
||||
ordered by *last* observation, and `otnF` survives the move. This is why the target's list is
|
||||
a permutation of the input's rather than an append.
|
||||
- **the list is capped at 20 entries per design-owner**, counted from the most recent end, and
|
||||
the cap is enforced *after every single record call*, not once per turn. On a player with more
|
||||
than 20 designs in service this thrashes: entries are evicted and re-created inside one sweep,
|
||||
and each re-creation resets `otnF` to the current turn. That is measured, not inferred — see
|
||||
§3.2.
|
||||
|
||||
### 2.3 The tech and weapon arms
|
||||
|
||||
The same function then builds three lists off the design and feeds two of them to
|
||||
`RecordObservedTech` `0x007ba1a0` (lane X's function) and one to `RecordObservedWeapon`
|
||||
`0x007be1b0`:
|
||||
|
||||
```
|
||||
0x007be4af FUN_00862c90(&v, design) -> for each: RecordObservedTech(player, owner, x) 0x007be4e1
|
||||
0x007be50d FUN_008629b0(&v, design) -> for each: RecordObservedTech(player, owner, x) 0x007be535
|
||||
0x007be561 FUN_008626a0(&v, design) -> for each: RecordObservedWeapon(player, owner, x) 0x007be591
|
||||
```
|
||||
|
||||
All three are ~600–700-byte `std::set` builders (`operator new 0x14` red-black nodes) walking
|
||||
the design's section array at `Design+0x2c`/`+0xac` and `+0x3c`. They are **not decoded**, and
|
||||
they are the dependency §4 names.
|
||||
|
||||
---
|
||||
|
||||
## 3. The gate, and the two guards the corpus forced
|
||||
|
||||
### 3.1 The visibility gate is unexercised on both reference pairs — say so out loud (rule 6, rule 28)
|
||||
|
||||
`Ship+0x54` is not on the wire, so the phase's real gate cannot be read from a save. It does not
|
||||
have to be, on these two pairs, because **no player observes another player's ship on either of
|
||||
them**:
|
||||
|
||||
- rich turn: player 16's twelve `opid = 32` records all keep `otnL = 27`, and player 32's one
|
||||
`opid = 16` record keeps `otnL = 25`. Every record that moves is a player's own design.
|
||||
- canonical pair: the single moving record is player 32's own design 18 (lane PL's M3).
|
||||
|
||||
So this implementation stands the gate in for **`ship.PlrID == player.id`**, and that is a
|
||||
**hypothesis with a named falsifier**: the first save in which one empire's fleet stands in
|
||||
sensor range of another's and a foreign `odes` record moves. It is not a reading of the gate and
|
||||
must not be quoted as one. What it *is* is the smallest rule that is correct on every state the
|
||||
corpus contains — and lane PL's M3 said the same thing from the other end ("not an intel pass").
|
||||
|
||||
### 3.2 The NPC guard — `owner->+0xfb && !owner->+0xfc`
|
||||
|
||||
The two bytes are consecutive `ServerPlayer` bools next to `RebAI`, which lane T pinned at
|
||||
`+0xfc` (`ProcessTurn` phase 8: `if (RebAI(+0xfc)) RebOutMod = clamp(...)`). The wire writes
|
||||
`Elim, NPC, RebAI, ReqCL` consecutively, so `+0xfb` is `NPC`. Read as
|
||||
**"a design owned by an NPC that is not a rebel AI is never recorded"**, and the corpus agrees:
|
||||
|
||||
| save | player | kind | own designs | own `odes` records |
|
||||
|---|---|---|---:|---:|
|
||||
| `ad-turn27` | 32 "The Eternal Empire" | not NPC | 46 | 20 |
|
||||
| `ad-turn27` | 16 "re" | not NPC | 6 | 1 |
|
||||
| `ad-turn27` | 528 "Alien Menace" | **NPC, not rebel** | 19 | **0** |
|
||||
| `ad-turn27` | 576 "Independent Colony" | **NPC, not rebel** | 1 | **0** |
|
||||
|
||||
Every `odes` record in the corpus, on every player, names a design owned by 16 or 32 — the two
|
||||
non-NPC empires. The four NPC factions own 26 designs between them and not one of them has ever
|
||||
been observed by anybody.
|
||||
|
||||
**Without this guard the canonical pair regresses by 4 leaves** (player 528 gains four records),
|
||||
which is P5 and is the reason the canonical pair is not a formality here.
|
||||
|
||||
### 3.3 What is *not* modelled
|
||||
|
||||
`0x0080baf0(design)` and `Design::HasFlag(design, 0x400)` are two further early returns that
|
||||
this implementation does not evaluate — the first is an unnamed predicate on the design, the
|
||||
second a design flag. Both are **assumed false** for every design in the corpus, on the evidence
|
||||
that the simulation reproduces the target list without them. That is an argument from a
|
||||
sufficient model, not from having read the flags, and it is recorded as such.
|
||||
|
||||
---
|
||||
|
||||
## 4. Named dependency: the tech and weapon arms are NOT independently closable
|
||||
|
||||
CV's ranking says rank 4 has "no upstream dependency". That is right for the `odes` half and
|
||||
**wrong for the other 24 leaves in the group**, in two separate ways. Both are named here and
|
||||
neither is attempted (scope discipline).
|
||||
|
||||
**(a) `otch` / `owep` need three undecoded set builders.** The obvious wire candidate is the
|
||||
per-section `DOpts` list, which `sots-engine`'s own `game::design::applied_techs` already
|
||||
documents as "exactly the save's `DOpts` list: hull-class tech, `requires_tech` in file order,
|
||||
then the chosen option". Measured against the reference turn, the union of `DOpts` over the
|
||||
designs player 32 observes covers **13 of the 18 tech names that move** and misses five —
|
||||
`WEP_GrnLas`, `WEP_PlsmCan`, `WEP_Dsrptr` (three weapon techs), `CCC_BtlCmp`, and the one
|
||||
**newly appended** record, `BIO_TerBac`. So `DOpts` is one of the three lists and not the whole
|
||||
of them; the other two (`0x008629b0`, `0x008626a0`) are `std::set<std::string>` builders over
|
||||
the design's weapon banks and would have to be decoded, and their **set ordering is
|
||||
load-bearing** because it decides the append order of any new `otch` element.
|
||||
|
||||
**(b) The `odes` half itself is capped by ship construction.** Two of the designs the target
|
||||
observes — 1826 "Egg Thief Mk 3" and 1522 "Bravestar Mk 2" — have **zero ships in the input and
|
||||
their first ships in the target** (4 and 1). No phase in this engine builds a ship (CV rank 8=,
|
||||
`M2` in `players-residual.md`), so those two observations cannot happen here, and because the
|
||||
list is capped at 20 per owner their absence also stops the two evictions (546 "Warrior Mk 6",
|
||||
770 "Beaten Shield Mk 2") that the target performs. That is the whole of the 21-leaf residual.
|
||||
|
||||
**The oracle run proves the mechanism is not the residual.** Feeding the same implementation the
|
||||
**target's** post-turn fleet/ship state instead of the input's leaves **1 leaf, not 21** —
|
||||
`Player[32]/odes/.[18]/otnF`, where this model writes 28 (the entry was evicted and re-created
|
||||
inside the sweep) and the target holds 27. So on the rich turn the mechanism is exact on 20 of
|
||||
21 records and the gap is ship construction, not `T34`.
|
||||
|
||||
---
|
||||
|
||||
## 5. Results
|
||||
|
||||
*(filled in after the run — see §5.1 onward)*
|
||||
|
||||
---
|
||||
|
||||
## 6. Reproducing
|
||||
|
||||
*(filled in after the run)*
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -58,13 +58,8 @@ ROWS = [
|
|||
"every call; only 20 distinct states across 4,437 calls"),
|
||||
("TechTree::ProcessResearch + unlock cascade", "compared",
|
||||
"35 calls across 3 workloads, 0 divergences, tracecmp exit 0; advance prediction held on a "
|
||||
"changed workload (unlock costs no earlier report contained); REPLACE ATTEMPTED live (lane "
|
||||
"CR): ours ran instead of the original on a real completion and produced all 13 tech-tree "
|
||||
"leaves the turn moves, but the save oracle missed by 16 leaves",
|
||||
"compare only. The replace attempt failed on ServerPlayer::OnTechResearched, not on the "
|
||||
"research model: 5 player tech-effect fields, 1 ObservedTech element and 2 event records, "
|
||||
"plus 5 derived leaves. Gated on B2. Thin: 1 completion, 1 tech, 2 of 3 calls allocate zero "
|
||||
"points, and the RNG region did not move at all on the replace workload"),
|
||||
"changed workload (unlock costs no earlier report contained)",
|
||||
"compare only, never replaced"),
|
||||
("ServerPlayer::OnTechResearched", "compared",
|
||||
"3 completions, 0 div; float32 confirmed bit-for-bit on the game",
|
||||
"compare only; RollResearchEvent's branch has fired once in four sessions"),
|
||||
|
|
|
|||
|
|
@ -15,21 +15,11 @@
|
|||
# Usage: tools/gate.sh [--fresh] --fresh: rm -rf the remote build dirs first (rule 24)
|
||||
set -u
|
||||
|
||||
# One gate at a time. Lane DW saw up to FOUR `gate.sh --fresh` runs concurrently, all rsyncing
|
||||
# into the same remote tree and rm -rf'ing its build dirs -- rule 24's shape with no lock, and a
|
||||
# way to report a build that is half someone else's. Every lane runs from this host, so a local
|
||||
# flock is sufficient. Waits up to 30 min, then fails loudly rather than running unlocked.
|
||||
if [ -z "${SOTS_GATE_LOCKED:-}" ]; then
|
||||
exec env SOTS_GATE_LOCKED=1 flock -w 1800 /tmp/sots-gate.lock "$0" "$@" \
|
||||
|| { echo "GATE FAIL could not acquire /tmp/sots-gate.lock within 30 min"; exit 2; }
|
||||
fi
|
||||
|
||||
ENGINE="${ENGINE:-$HOME/sots-engine}"
|
||||
RE="${RE:-$HOME/sots-re}"
|
||||
CT=111
|
||||
REMOTE_TREE=/srv/re-lab/build/sots-engine
|
||||
REMOTE_CORPUS=/srv/re-lab/saves-corpus
|
||||
REMOTE_DATA=/srv/re-lab/gob-extract # the extracted asset tree; game_design_census needs it
|
||||
FRESH=0
|
||||
[ "${1:-}" = "--fresh" ] && FRESH=1
|
||||
|
||||
|
|
@ -59,25 +49,15 @@ ssh spicy "pct exec $CT -- mkdir -p $REMOTE_CORPUS && tar -C /tmp/sots-corpus -c
|
|||
NCORPUS=$(ct "ls $REMOTE_CORPUS | grep -c .sav")
|
||||
echo "GATE info corpus on CT111: $NCORPUS saves"
|
||||
|
||||
# 5. host build + tests, WITH the corpus AND the extracted data tree
|
||||
#
|
||||
# `cmd | tail -1` returns TAIL's status, not the command's -- so for a day this
|
||||
# script printed "GATE ok host-ctest" over a run with two FAILING tests, which is
|
||||
# rule 1's failure wearing this script's own clothes. Every step below captures
|
||||
# the real exit code first and only then trims the output.
|
||||
ct "cd $REMOTE_TREE && cmake -S . -B build-host -DCMAKE_BUILD_TYPE=Release >/tmp/gate-cfg.log 2>&1 && cmake --build build-host -j8 >/tmp/gate-build.log 2>&1; rc=\$?; tail -1 /tmp/gate-build.log; exit \$rc"; report host-build $?
|
||||
ct "cd $REMOTE_TREE/build-host && SOTS_SAVES_DIR=$REMOTE_CORPUS SOTS_DATA_DIR=$REMOTE_DATA ctest --output-on-failure >/tmp/gate-ctest.log 2>&1; rc=\$?; tail -15 /tmp/gate-ctest.log; exit \$rc"; report host-ctest $?
|
||||
# and prove the corpus tests RAN rather than skipped. The check is scoped to the
|
||||
# tests gated on the CORPUS (they name SOTS_SAVES_DIR when they skip); every other
|
||||
# skip is listed below it by name, because a skip nobody reads is how this started.
|
||||
SKIPPED=$(ct "cd $REMOTE_TREE/build-host && SOTS_SAVES_DIR=$REMOTE_CORPUS SOTS_DATA_DIR=$REMOTE_DATA ctest -V 2>&1 | grep -c SOTS_SAVES_DIR")
|
||||
# 5. host build + tests, WITH the corpus
|
||||
ct "cd $REMOTE_TREE && cmake -S . -B build-host -DCMAKE_BUILD_TYPE=Release >/dev/null 2>&1 && cmake --build build-host -j8 2>&1 | tail -1"; report host-build $?
|
||||
ct "cd $REMOTE_TREE/build-host && SOTS_SAVES_DIR=$REMOTE_CORPUS ctest --output-on-failure 2>&1 | tail -15"; report host-ctest $?
|
||||
# and prove the corpus tests RAN rather than skipped
|
||||
SKIPPED=$(ct "cd $REMOTE_TREE/build-host && SOTS_SAVES_DIR=$REMOTE_CORPUS ctest -V 2>&1 | grep -c 'unset, skipped'")
|
||||
if [ "${SKIPPED:-1}" -ne 0 ]; then echo "GATE FAIL corpus tests skipped ($SKIPPED) -- the gate is hollow"; status=1; else echo "GATE ok corpus tests ran (0 skipped)"; fi
|
||||
ct "cd $REMOTE_TREE/build-host && SOTS_SAVES_DIR=$REMOTE_CORPUS SOTS_DATA_DIR=$REMOTE_DATA ctest -V 2>&1 | grep skipped" | sed 's/^/GATE info skip: /'
|
||||
|
||||
# 6. shim cross-build -- same exit-code discipline as step 5. The `ls` at the end
|
||||
# is a second, independent check (the artefact exists), not the build's verdict:
|
||||
# without --fresh a DLL from an earlier run would satisfy it on its own.
|
||||
ct "cd $REMOTE_TREE && cmake -S . -B build-shim -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-mingw-i686.cmake -DCMAKE_BUILD_TYPE=Release >/tmp/gate-shim-cfg.log 2>&1; rc=\$?; cmake --build build-shim -j8 >/tmp/gate-shim.log 2>&1 || rc=1; tail -1 /tmp/gate-shim.log; ls -la build-shim/binkw32.dll || rc=1; exit \$rc"; report shim-cross-build $?
|
||||
# 6. shim cross-build
|
||||
ct "cd $REMOTE_TREE && cmake -S . -B build-shim -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-mingw-i686.cmake -DCMAKE_BUILD_TYPE=Release >/dev/null 2>&1 && cmake --build build-shim -j8 2>&1 | tail -1 && ls -la build-shim/binkw32.dll"; report shim-cross-build $?
|
||||
|
||||
echo "== gate: $([ $status -eq 0 ] && echo GREEN || echo RED)"
|
||||
exit $status
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,28 +0,0 @@
|
|||
## tracecmp report: N.trace.jsonl
|
||||
|
||||
- build: cr-618ccb1-20260909T131556Z started: 2026-09-09T13:33:54Z inline_max: 256
|
||||
- calls: 4 compared: 3 diverged: 0 invalid records: 0 warnings: 0
|
||||
- coverage: 3 guarded call(s), 6 undeclared write(s) in 1 call(s); 0 hook(s) unstated, 0 contradicted
|
||||
|
||||
| hook | calls | modes | compared | diverged | errors |
|
||||
|---|---|---|---|---|---|
|
||||
| Game::TechTree::ProcessResearch | 3 | compare:3 | 3 | 0 | 0 |
|
||||
| Shim::SelfTest::Fill | 1 | trace:1 | 0 | 0 | 0 |
|
||||
|
||||
### coverage
|
||||
|
||||
| hook | verdict | compared regions | guards | undeclared writes | unmodelled |
|
||||
|---|---|---|---|---|---|
|
||||
| Game::TechTree::ProcessResearch | partial | events, node[0], node[105], node[106], node[107], node[108], +271 | player, tree_header | 6 in 1 call(s) | 8 |
|
||||
| Shim::SelfTest::Fill | complete | buf | - | not watched | 0 |
|
||||
|
||||
#### Game::TechTree::ProcessResearch — not checked by this run
|
||||
- (medium) 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 — 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 [region:events]
|
||||
- (low) composes EVENT_TECHS_UNLOCKED's message from the unlocked techs' names — 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 [region:events]
|
||||
- (high) TechTree::SetResearched in REPLACE mode: only its TechTree half runs, and only when research.replace_cascade=on — with the flag OFF (the default) nothing of the cascade runs, so a replace run leaves the completed node unstamped and no tech unlocked. With it ON, the four TechNode words (costRP, turnAvailable, turnResearched, order) and the tree's completion-order counter are written live, and the ServerPlayer half is still not: no event is posted, no ObservedTech element is appended and no tech effect is applied. Neither setting is a full displacement of the completion path; the pair measures where the boundary is [guard:player, guard:tree_header]
|
||||
- (high) 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 — 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 [guard:player]
|
||||
- (high) the research-event branch RollResearchEvent takes when its roll beats the odds (ServerPlayer::OnResearchRollSucceeded: the plague and AI-rebellion event paths) — 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 [region:rng]
|
||||
- (medium) constructs the ObservedTech element it appends to ServerPlayer+0x274 — `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 [region:observed_techs]
|
||||
- (low) the tree's completion-order counter (TechTree+0x20) is read pre-call, not modelled as a region — 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 [guard:tree_header]
|
||||
- (low) writes a completion line to the game log — log text is not simulation state
|
||||
- guard hits in compare mode: player+0x10c:3, player+0x110:3, player+0x114:3, player+0x124:3, player+0x294:4, tree_header+0x20:1
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,27 +0,0 @@
|
|||
## tracecmp report: R0.trace.jsonl
|
||||
|
||||
- build: cr-618ccb1-20260909T131556Z started: 2026-09-09T13:51:31Z inline_max: 256
|
||||
- calls: 4 compared: 0 diverged: 0 invalid records: 0 warnings: 0
|
||||
- coverage: 3 guarded call(s), 0 undeclared write(s) in 0 call(s); 0 hook(s) unstated, 0 contradicted
|
||||
|
||||
| hook | calls | modes | compared | diverged | errors |
|
||||
|---|---|---|---|---|---|
|
||||
| Game::TechTree::ProcessResearch | 3 | replace:3 | 0 | 0 | 0 |
|
||||
| Shim::SelfTest::Fill | 1 | trace:1 | 0 | 0 | 0 |
|
||||
|
||||
### coverage
|
||||
|
||||
| hook | verdict | compared regions | guards | undeclared writes | unmodelled |
|
||||
|---|---|---|---|---|---|
|
||||
| Game::TechTree::ProcessResearch | partial | events, node[0], node[105], node[106], node[107], node[108], +271 | player, tree_header | 0 | 8 |
|
||||
| Shim::SelfTest::Fill | complete | buf | - | not watched | 0 |
|
||||
|
||||
#### Game::TechTree::ProcessResearch — not checked by this run
|
||||
- (medium) 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 — 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 [region:events]
|
||||
- (low) composes EVENT_TECHS_UNLOCKED's message from the unlocked techs' names — 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 [region:events]
|
||||
- (high) TechTree::SetResearched in REPLACE mode: only its TechTree half runs, and only when research.replace_cascade=on — with the flag OFF (the default) nothing of the cascade runs, so a replace run leaves the completed node unstamped and no tech unlocked. With it ON, the four TechNode words (costRP, turnAvailable, turnResearched, order) and the tree's completion-order counter are written live, and the ServerPlayer half is still not: no event is posted, no ObservedTech element is appended and no tech effect is applied. Neither setting is a full displacement of the completion path; the pair measures where the boundary is [guard:player, guard:tree_header]
|
||||
- (high) 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 — 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 [guard:player]
|
||||
- (high) the research-event branch RollResearchEvent takes when its roll beats the odds (ServerPlayer::OnResearchRollSucceeded: the plague and AI-rebellion event paths) — 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 [region:rng]
|
||||
- (medium) constructs the ObservedTech element it appends to ServerPlayer+0x274 — `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 [region:observed_techs]
|
||||
- (low) the tree's completion-order counter (TechTree+0x20) is read pre-call, not modelled as a region — 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 [guard:tree_header]
|
||||
- (low) writes a completion line to the game log — log text is not simulation state
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,28 +0,0 @@
|
|||
## tracecmp report: R1.trace.jsonl
|
||||
|
||||
- build: cr-618ccb1-20260909T131556Z started: 2026-09-09T13:42:14Z inline_max: 256
|
||||
- calls: 4 compared: 0 diverged: 0 invalid records: 0 warnings: 0
|
||||
- coverage: 3 guarded call(s), 1 undeclared write(s) in 1 call(s); 0 hook(s) unstated, 0 contradicted
|
||||
|
||||
| hook | calls | modes | compared | diverged | errors |
|
||||
|---|---|---|---|---|---|
|
||||
| Game::TechTree::ProcessResearch | 3 | replace:3 | 0 | 0 | 0 |
|
||||
| Shim::SelfTest::Fill | 1 | trace:1 | 0 | 0 | 0 |
|
||||
|
||||
### coverage
|
||||
|
||||
| hook | verdict | compared regions | guards | undeclared writes | unmodelled |
|
||||
|---|---|---|---|---|---|
|
||||
| Game::TechTree::ProcessResearch | partial | events, node[0], node[105], node[106], node[107], node[108], +271 | player, tree_header | 1 in 1 call(s) | 8 |
|
||||
| Shim::SelfTest::Fill | complete | buf | - | not watched | 0 |
|
||||
|
||||
#### Game::TechTree::ProcessResearch — not checked by this run
|
||||
- (medium) 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 — 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 [region:events]
|
||||
- (low) composes EVENT_TECHS_UNLOCKED's message from the unlocked techs' names — 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 [region:events]
|
||||
- (high) TechTree::SetResearched in REPLACE mode: only its TechTree half runs, and only when research.replace_cascade=on — with the flag OFF (the default) nothing of the cascade runs, so a replace run leaves the completed node unstamped and no tech unlocked. With it ON, the four TechNode words (costRP, turnAvailable, turnResearched, order) and the tree's completion-order counter are written live, and the ServerPlayer half is still not: no event is posted, no ObservedTech element is appended and no tech effect is applied. Neither setting is a full displacement of the completion path; the pair measures where the boundary is [guard:player, guard:tree_header]
|
||||
- (high) 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 — 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 [guard:player]
|
||||
- (high) the research-event branch RollResearchEvent takes when its roll beats the odds (ServerPlayer::OnResearchRollSucceeded: the plague and AI-rebellion event paths) — 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 [region:rng]
|
||||
- (medium) constructs the ObservedTech element it appends to ServerPlayer+0x274 — `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 [region:observed_techs]
|
||||
- (low) the tree's completion-order counter (TechTree+0x20) is read pre-call, not modelled as a region — 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 [guard:tree_header]
|
||||
- (low) writes a completion line to the game log — log text is not simulation state
|
||||
- guard hits in replace mode: tree_header+0x20:1
|
||||
|
|
@ -20,7 +20,6 @@ those columns is an observation, not a certification.
|
|||
| `ref-turn2.sav` `ab4ac2d7…` | one End Turn | load | `bb4fd9ac…` | `978041ac…` | 5 + 1 | runs A–E; reproduced by lane H after everything changed |
|
||||
| `ar-turn37-816raiders.sav` `b6f4e05f…` | End Turn, **auto-resolve peacefully**, End Turn | load | `15b99255…` | `7a8b3d5e…` | **4** | lane AR ×3 `hooks=off`, lane BS ×1 instrumented |
|
||||
| `ar-oracle-A-pre.sav` `15b99255…` | one End Turn | **load** | `33e30092…` | `4c356f59…` | **3** | lane BQ ×2 `hooks=off`, lane BS ×1 instrumented |
|
||||
| `turn3-state.sav` `978041ac…` | one End Turn | **load** | `e00eed0c…` | `79df5047…` | **3** | lane CR ×2 `hooks=off`, ×1 compare-instrumented |
|
||||
|
||||
**The second and third rows are the same lineage and they do not agree with each other.** Row 2's
|
||||
second turn reached by continuation gives `7a8b3d5e…`; the identical turn reached by *loading* row 2's
|
||||
|
|
@ -30,22 +29,6 @@ boundary, and it is why the route column exists.
|
|||
**Row 3 is the standalone's first trade-raid pair** — one End Turn, no encounter, four raid rolls at
|
||||
one word each.
|
||||
|
||||
**Row 4 is the first pair on a turn that completes a research tech** (lane CR, 2026-09-09).
|
||||
`turn3-state.sav` is the *output* of row 1 — the `(Autosave).sav` that `ref-turn2` + one End Turn
|
||||
produces — and the turn it starts is the one where `Player[32 "Fane Lao"]` completes tech 144
|
||||
`IND_Waldo` and the cascade unlocks three nodes. Row 1's own turn does **not** complete anything
|
||||
(`unlock-b3-t1.md`: `0 undeclared write(s) in 0 call(s)`), so every research oracle before this row
|
||||
was taken on a turn where the completion path did not run. Exposure at entry: none of the three
|
||||
players with an AI client (32, 496, 512) has `ResTNm == ''`; `NumDes` does not move; two ships
|
||||
complete and join existing fleets; the four factions at 528–576 carry the empty-`ResTNm` signature
|
||||
inertly (`Status 0`, no client). Two ships completing *and* three fleets changing did **not** expose
|
||||
this turn — a reminder that 26(c) is a screen and the control is the decision.
|
||||
|
||||
Masks for row 4, measured against the input: **exactly `/Summary/Checksum` and `Player.Status 4 → 0`
|
||||
on the four live players. No `/CD[1]/NPrvVa` term** — this state's `CD[1]` diplomacy block is
|
||||
early-game and the leaf does not move, so the documented `--mask resave` rule holds here in its
|
||||
original form.
|
||||
|
||||
### Masks that must be on the line
|
||||
|
||||
- `Player.Status` (4 → 0 on load) and the derived `Summary.Checksum`.
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -37,11 +37,3 @@ b6f4e05ff226eabd1695003b36293553642553cea96ef417364393e2332a7094 verify/results
|
|||
1c8baa27680809d585ab1728391e82729642d32aaedffd5bf95b616f0a11a436 verify/results/saves/ad-turn27-two-raiders.sav
|
||||
e913ff41188211c02d536da616337544e64133996cd7cc7a6521a8df1960226f verify/results/saves/bp-pinA-turn28.sav
|
||||
724528ffde9a7514b69ab9e82ed3b8c8ade63d622c0720de30503a73a92df11e verify/results/saves/bp-pinB-turn28.sav
|
||||
|
||||
# Lane CR, 2026-09-09 -- VM145. Input turn3-state.sav (= the (Autosave).sav of certified-pairs
|
||||
# row 1), one End Turn, LOAD route. Build cr-618ccb1-20260909T131556Z, shimdist-cr.
|
||||
# C1/C2 hooks=off (two fresh processes), N compare, R0/R1 replace.
|
||||
e00eed0c03a31d27a81b7470a9dcc9ba08a2ac48c20baeee4f34749164743e3f 67212 (Autosave EndTurn).sav C1 == C2 == N == R0 == R1
|
||||
79df50475a7b83afa927d992b9f030dcf45710f4bda0133b8b1fa4800a72e420 67811 (Autosave).sav C1 == C2 == N [THE ORACLE]
|
||||
6b51db992b158caa5424d71b2dccf72924af7198b4165bfcfc870e0d438fb6d5 67511 (Autosave).sav R0 replace, research.replace_cascade=off -> 27 leaves
|
||||
8a4309ee4fe0b3177a2820600b5016c7c256d0f51b065df469ecd0b4f2342235 67537 (Autosave).sav R1 replace, research.replace_cascade=on -> 16 leaves
|
||||
|
|
|
|||
|
|
@ -1,118 +0,0 @@
|
|||
09:33:54.650 [tid 880] ==== sots-engine shim (binkw32 proxy) build cr-618ccb1-20260909T131556Z ====
|
||||
09:33:54.650 [tid 880] exe: C:\SOTS\Sword of the Stars.exe
|
||||
09:33:54.650 [tid 880] exe base=0x00f40000 (link-time image base 0x00400000, ASLR delta +11796480) pid=20996 shim=71d70000
|
||||
09:33:54.650 [tid 880] addresses: Source: sots-re ghidra/addresses.json @ aa8d3fb, generated 2026-09-09 by tools/gen_addresses.py
|
||||
09:33:54.650 [tid 880] config: hooks=trace
|
||||
09:33:54.650 [tid 880] config: hook.Game::EncounterDetect::AssignContacts=off
|
||||
09:33:54.650 [tid 880] config: hook.Game::EncounterDetect::ProcessTeamRecord=off
|
||||
09:33:54.650 [tid 880] config: hook.Game::SVSOSlaversRefuel::UpdateDifficultyTier=off
|
||||
09:33:54.650 [tid 880] config: hook.Game::SVSOSwarmQueen::OnTurnBegin=off
|
||||
09:33:54.650 [tid 880] config: hook.Game::SVSOSwarmQueen::RegisterHives=off
|
||||
09:33:54.650 [tid 880] config: hook.Game::SVSOSwarmQueen::TickHives=off
|
||||
09:33:54.650 [tid 880] config: hook.Game::SectionDictionary::SectionDictionary=off
|
||||
09:33:54.650 [tid 880] config: hook.Game::ServerPlayer::ComputeBudget=off
|
||||
09:33:54.650 [tid 880] config: hook.Game::ServerPlayer::OnTechResearched=off
|
||||
09:33:54.650 [tid 880] config: hook.Game::ServerPlayer::ProcessTurn=off
|
||||
09:33:54.650 [tid 880] config: hook.Game::ServerSystem::ComputeTotalOutput=off
|
||||
09:33:54.650 [tid 880] config: hook.Game::ServerSystem::GroupOutput=off
|
||||
09:33:54.650 [tid 880] config: hook.Game::ServerSystem::ProcessTurn=off
|
||||
09:33:54.650 [tid 880] config: hook.Game::StrategyApp::RunAI=off
|
||||
09:33:54.650 [tid 880] config: hook.Game::StrategyHost::Autosave=off
|
||||
09:33:54.650 [tid 880] config: hook.Game::StrategyServer::ApplyEncounterResult=off
|
||||
09:33:54.650 [tid 880] config: hook.Game::StrategyServer::BeginProcessTurn=off
|
||||
09:33:54.650 [tid 880] config: hook.Game::StrategyServer::MoveFleet=off
|
||||
09:33:54.650 [tid 880] config: hook.Game::StrategyServer::NodeLineDecay=off
|
||||
09:33:54.650 [tid 880] config: hook.Game::StrategyServer::OnAllCombatDone_Tail=off
|
||||
09:33:54.650 [tid 880] config: hook.Game::StrategyServer::ProcessFleetMovement=off
|
||||
09:33:54.650 [tid 880] config: hook.Game::StrategyServer::ProcessNodeSpaceTravel=off
|
||||
09:33:54.650 [tid 880] config: hook.Game::StrategyServer::ProcessTurn=off
|
||||
09:33:54.650 [tid 880] config: hook.Game::WeaponDictionary::Init=off
|
||||
09:33:54.650 [tid 880] config: hook.Mars::GlobalConsts::LoadFile=off
|
||||
09:33:54.650 [tid 880] config: hook.Mars::RNG::Seed=off
|
||||
09:33:54.650 [tid 880] config: hook.Game::TechTree::ProcessResearch=compare
|
||||
09:33:54.650 [tid 880] config: research.replace_cascade=off
|
||||
09:33:54.650 [tid 880] config: trace.path=C:\SOTS\shim.trace.jsonl
|
||||
09:33:54.650 [tid 880] config: trace.inline_max=256
|
||||
09:33:54.650 [tid 880] config: trace.flush=always
|
||||
09:33:54.728 [tid 880] trace: C:\SOTS\shim.trace.jsonl (default mode trace, inline_max 256, flush always)
|
||||
09:33:54.728 [tid 880] hook: Mars_Application_Initialize rva=0x004a0e50 -> va=013e0e50
|
||||
09:33:54.728 [tid 880] hook: MH_Initialize -> MH_OK
|
||||
09:33:54.728 [tid 880] hook: MH_CreateHook -> MH_OK (trampoline=00a30fe0)
|
||||
09:33:54.759 [tid 880] hook: MH_EnableHook -> MH_OK
|
||||
09:33:54.759 [tid 880] cfg: GlobalConsts hook ready (scale constant 0.017453292519943295)
|
||||
09:33:54.759 [tid 880] hook: Mars::GlobalConsts::LoadFile rva=0x004b73c0 mode=off (not installed)
|
||||
09:33:54.759 [tid 880] dict: dictionaries hook ready (crt new=73e7232b delete=73e70174)
|
||||
09:33:54.759 [tid 880] hook: Game::WeaponDictionary::Init rva=0x0019a4c0 mode=off (not installed)
|
||||
09:33:54.759 [tid 880] hook: Game::SectionDictionary::SectionDictionary rva=0x00176f40 mode=off (not installed)
|
||||
09:33:54.759 [tid 880] research: ProcessResearch hook ready (Cost=010bda00, node=0x34, rng=0x9cc, fpu_cw=0x027f, replace_cascade=off)
|
||||
09:33:54.759 [tid 880] hook: Game::TechTree::ProcessResearch rva=0x001876c0 -> va=010c76c0 MH_CreateHook -> MH_OK (trampoline=00a30fc0)
|
||||
09:33:54.775 [tid 880] hook: Game::TechTree::ProcessResearch MH_EnableHook -> MH_OK mode=compare
|
||||
09:33:54.775 [tid 880] techfx: OnTechResearched hook ready (regions=15, gate=0/0, fpu_cw=0x027f)
|
||||
09:33:54.775 [tid 880] hook: Game::ServerPlayer::OnTechResearched rva=0x00491790 mode=off (not installed)
|
||||
09:33:54.775 [tid 880] hook: Game::ServerPlayer::ComputeBudget rva=0x00463030 mode=off (not installed)
|
||||
09:33:54.775 [tid 880] hook: Game::ServerSystem::ProcessTurn rva=0x003598e0 mode=off (not installed)
|
||||
09:33:54.775 [tid 880] hook: Game::ServerSystem::GroupOutput rva=0x0034b7a0 mode=off (not installed)
|
||||
09:33:54.775 [tid 880] hook: Game::ServerSystem::ComputeTotalOutput rva=0x00350480 mode=off (not installed)
|
||||
09:33:54.775 [tid 880] player_turn: ServerPlayer::ProcessTurn hook armed (ratio helper at 010be950)
|
||||
09:33:54.775 [tid 880] hook: Game::ServerPlayer::ProcessTurn rva=0x00491340 mode=off (not installed)
|
||||
09:33:54.775 [tid 880] hook: Game::StrategyServer::MoveFleet rva=0x003d9ee0 mode=off (not installed)
|
||||
09:33:54.775 [tid 880] hook: Game::StrategyServer::ProcessFleetMovement rva=0x003da9a0 mode=off (not installed)
|
||||
09:33:54.775 [tid 880] hook: Game::StrategyHost::Autosave rva=0x00495210 mode=off (not installed)
|
||||
09:33:54.775 [tid 880] hook: Game::StrategyServer::ProcessTurn rva=0x003dc6c0 mode=off (not installed)
|
||||
09:33:54.775 [tid 880] hook: Game::StrategyServer::OnAllCombatDone_Tail rva=0x003d92a0 mode=off (not installed)
|
||||
09:33:54.775 [tid 880] hook: Game::StrategyServer::ApplyEncounterResult rva=0x003d8920 mode=off (not installed)
|
||||
09:33:54.775 [tid 880] hook: Game::StrategyServer::NodeLineDecay rva=0x003ae010 mode=off (not installed)
|
||||
09:33:54.775 [tid 880] hook: Game::StrategyServer::ProcessNodeSpaceTravel rva=0x003a0e20 mode=off (not installed)
|
||||
09:33:54.775 [tid 880] hook: Game::EncounterDetect::AssignContacts rva=0x003aa240 mode=off (not installed)
|
||||
09:33:54.775 [tid 880] hook: Game::EncounterDetect::ProcessTeamRecord rva=0x003ca640 mode=off (not installed)
|
||||
09:33:54.775 [tid 880] hook: Game::StrategyServer::BeginProcessTurn rva=0x003d98e0 mode=off (not installed)
|
||||
09:33:54.775 [tid 880] hook: Game::SVSOSwarmQueen::OnTurnBegin rva=0x00129930 mode=off (not installed)
|
||||
09:33:54.775 [tid 880] hook: Game::SVSOSwarmQueen::RegisterHives rva=0x00127630 mode=off (not installed)
|
||||
09:33:54.775 [tid 880] hook: Game::SVSOSwarmQueen::TickHives rva=0x00127770 mode=off (not installed)
|
||||
09:33:54.775 [tid 880] hook: Game::SVSOSlaversRefuel::UpdateDifficultyTier rva=0x00115820 mode=off (not installed)
|
||||
09:33:54.775 [tid 880] hook: Mars::RNG::Seed rva=0x0009fdf0 mode=off (not installed)
|
||||
09:33:54.775 [tid 880] hook: Game::StrategyApp::RunAI rva=0x004706f0 mode=off (not installed)
|
||||
09:33:54.806 [tid 880] drawsite: Mars::RNG::NextFloat rva=0x0007d830 -> va=00fbd830 create=MH_OK enable=MH_OK
|
||||
09:33:54.822 [tid 880] drawsite: Mars::RNG::NextInt rva=0x000271c0 -> va=00f671c0 create=MH_OK enable=MH_OK
|
||||
09:33:54.853 [tid 880] drawsite: Mars::RNG::Chance rva=0x004e6dd0 -> va=01426dd0 create=MH_OK enable=MH_OK
|
||||
09:33:54.869 [tid 880] drawsite: Mars::RNG::NextUInt rva=0x000f7670 -> va=01037670 create=MH_OK enable=MH_OK
|
||||
09:33:54.884 [tid 880] drawsite: Mars::RNG::FloatRange rva=0x0007d8a0 -> va=00fbd8a0 create=MH_OK enable=MH_OK
|
||||
09:33:54.916 [tid 880] drawsite: Mars::RNG::IntRangeBell rva=0x004e6d80 -> va=01426d80 create=MH_OK enable=MH_OK
|
||||
09:33:54.931 [tid 880] drawsite: Mars::RNG::GaussianRange rva=0x004e6e30 -> va=01426e30 create=MH_OK enable=MH_OK
|
||||
09:33:54.931 [tid 880] probe: installing 12 of 12 (probes= in shim.cfg)
|
||||
09:33:54.947 [tid 880] probe: Game::ServerSpyManager::vslot13 rva=0x004877b0 -> va=013c77b0 create=MH_OK enable=MH_OK
|
||||
09:33:54.963 [tid 880] probe: Game::ServerSpyManager::vslot14 rva=0x0048db80 -> va=013cdb80 create=MH_OK enable=MH_OK
|
||||
09:33:54.994 [tid 880] probe: Game::ServerTradeManagerImpl::vslot13 rva=0x0048ef80 -> va=013cef80 create=MH_OK enable=MH_OK
|
||||
09:33:55.009 [tid 880] probe: Game::ServerTradeManagerImpl::vslot15 rva=0x0042cca0 -> va=0136cca0 create=MH_OK enable=MH_OK
|
||||
09:33:55.025 [tid 880] probe: Game::SpyManager::Slot13RngCallee rva=0x004408e0 -> va=013808e0 create=MH_OK enable=MH_OK
|
||||
09:33:55.041 [tid 880] probe: Game::TradeManager::Slot13RngCalleeA rva=0x00420ca0 -> va=01360ca0 create=MH_OK enable=MH_OK
|
||||
09:33:55.072 [tid 880] probe: Game::TradeManager::Slot13RngCalleeB rva=0x0048b440 -> va=013cb440 create=MH_OK enable=MH_OK
|
||||
09:33:55.088 [tid 880] probe: Game::ServerTradeManager::CreateRaidEncounter rva=0x004938a0 -> va=013d38a0 create=MH_OK enable=MH_OK
|
||||
09:33:55.103 [tid 880] probe: Game::ServerTradeManager::GenerateTradeRaidEncounters rva=0x00493290 -> va=013d3290 create=MH_OK enable=MH_OK
|
||||
09:33:55.134 [tid 880] probe: Game::ServerSpyManager::vslot15 [control] rva=0x00487f30 -> va=013c7f30 create=MH_OK enable=MH_OK
|
||||
09:33:55.150 [tid 880] probe: Game::ServerTradeManagerImpl::vslot14 [control] rva=0x004590d0 -> va=013990d0 create=MH_OK enable=MH_OK
|
||||
09:33:55.166 [tid 880] probe: Game::EncounterDetect::Run [control] rva=0x003cb080 -> va=0130b080 create=MH_OK enable=MH_OK
|
||||
09:33:55.166 [tid 880] watch: disabled (watch=off)
|
||||
09:33:55.166 [tid 880] aiorders: disabled (aiorders=off)
|
||||
09:33:55.166 [tid 880] fpu: module init, entry cw=0x027f 53bit-double/nearest; force=off value=0x0000 sample_ticks=on
|
||||
09:33:55.166 [tid 880] fpu: sample_turn=on (off releases StrategyServer::ProcessTurn for another hook)
|
||||
09:33:55.166 [tid 880] fpu: StrategyClient::EndTurn rva=0x00383be0 -> va=012c3be0 MH_CreateHook -> MH_OK (trampoline=00a30d40)
|
||||
09:33:55.197 [tid 880] fpu: StrategyClient::EndTurn MH_EnableHook -> MH_OK
|
||||
09:33:55.197 [tid 880] fpu: StrategyServer::BeginProcessTurn rva=0x003d98e0 -> va=013198e0 MH_CreateHook -> MH_OK (trampoline=00a30d20)
|
||||
09:33:55.213 [tid 880] fpu: StrategyServer::BeginProcessTurn MH_EnableHook -> MH_OK
|
||||
09:33:55.213 [tid 880] fpu: StrategyServer::ProcessTurn rva=0x003dc6c0 -> va=0131c6c0 MH_CreateHook -> MH_OK (trampoline=00a30d00)
|
||||
09:33:55.228 [tid 880] fpu: StrategyServer::ProcessTurn MH_EnableHook -> MH_OK
|
||||
09:33:55.228 [tid 880] fpu: DemoApp::OnTick rva=0x0049a640 -> va=013da640 MH_CreateHook -> MH_OK (trampoline=00a30ce0)
|
||||
09:33:55.259 [tid 880] fpu: DemoApp::OnTick MH_EnableHook -> MH_OK
|
||||
09:33:55.259 [tid 880] selftest: Shim::SelfTest::Fill mode=trace checksum=075ef0c3 records=1
|
||||
09:33:55.275 [tid 880] Application::Initialize called (this=00a88128)
|
||||
09:33:56.166 [tid 880] fpu: TICK BASELINE at OnTick (this=00a88128): cw=0x127f 53bit-double/nearest
|
||||
09:39:38.180 [tid 880] fpu: sample at StrategyClient::EndTurn (this=1e0711e8): cw=0x127f 53bit-double/nearest [no fpu.force configured]
|
||||
09:39:41.289 [tid 880] fpu: sample at StrategyClient::EndTurn (this=32c5e628): cw=0x127f 53bit-double/nearest [no fpu.force configured]
|
||||
09:39:41.336 [tid 880] fpu: sample at StrategyClient::EndTurn (this=32c58038): cw=0x127f 53bit-double/nearest [no fpu.force configured]
|
||||
09:39:41.383 [tid 880] fpu: sample at StrategyClient::EndTurn (this=32c5d798): cw=0x127f 53bit-double/nearest [no fpu.force configured]
|
||||
09:39:42.305 [tid 880] fpu: sample at StrategyServer::BeginProcessTurn (this=0d2908c8): cw=0x127f 53bit-double/nearest [no fpu.force configured]
|
||||
09:39:42.305 [tid 880] fpu: sample at StrategyServer::ProcessTurn (this=0d2908c8): cw=0x127f 53bit-double/nearest
|
||||
09:39:42.336 [tid 880] research: mode=compare steps=1 completions=1 overbudget=1166 cascade_possible=1 ok=1 cascade_completions=1 unlocked=3 otch_appends=1 roll_draws=0 failures=0 depth=0 name_unreadable=0
|
||||
09:39:42.383 [tid 880] research: mode=compare steps=1 completions=0 overbudget=0 cascade_possible=1 ok=1 cascade_completions=0 unlocked=0 otch_appends=0 roll_draws=0 failures=0 depth=0 name_unreadable=0
|
||||
09:39:42.398 [tid 880] research: mode=compare steps=1 completions=0 overbudget=0 cascade_possible=1 ok=1 cascade_completions=0 unlocked=0 otch_appends=0 roll_draws=0 failures=0 depth=0 name_unreadable=0
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
09:51:31.009 [tid 19724] ==== sots-engine shim (binkw32 proxy) build cr-618ccb1-20260909T131556Z ====
|
||||
09:51:31.009 [tid 19724] exe: C:\SOTS\Sword of the Stars.exe
|
||||
09:51:31.009 [tid 19724] exe base=0x00f40000 (link-time image base 0x00400000, ASLR delta +11796480) pid=20348 shim=71d70000
|
||||
09:51:31.009 [tid 19724] addresses: Source: sots-re ghidra/addresses.json @ aa8d3fb, generated 2026-09-09 by tools/gen_addresses.py
|
||||
09:51:31.009 [tid 19724] config: hooks=trace
|
||||
09:51:31.009 [tid 19724] config: hook.Game::EncounterDetect::AssignContacts=off
|
||||
09:51:31.009 [tid 19724] config: hook.Game::EncounterDetect::ProcessTeamRecord=off
|
||||
09:51:31.009 [tid 19724] config: hook.Game::SVSOSlaversRefuel::UpdateDifficultyTier=off
|
||||
09:51:31.009 [tid 19724] config: hook.Game::SVSOSwarmQueen::OnTurnBegin=off
|
||||
09:51:31.009 [tid 19724] config: hook.Game::SVSOSwarmQueen::RegisterHives=off
|
||||
09:51:31.009 [tid 19724] config: hook.Game::SVSOSwarmQueen::TickHives=off
|
||||
09:51:31.009 [tid 19724] config: hook.Game::SectionDictionary::SectionDictionary=off
|
||||
09:51:31.025 [tid 19724] config: hook.Game::ServerPlayer::ComputeBudget=off
|
||||
09:51:31.025 [tid 19724] config: hook.Game::ServerPlayer::OnTechResearched=off
|
||||
09:51:31.025 [tid 19724] config: hook.Game::ServerPlayer::ProcessTurn=off
|
||||
09:51:31.025 [tid 19724] config: hook.Game::ServerSystem::ComputeTotalOutput=off
|
||||
09:51:31.025 [tid 19724] config: hook.Game::ServerSystem::GroupOutput=off
|
||||
09:51:31.025 [tid 19724] config: hook.Game::ServerSystem::ProcessTurn=off
|
||||
09:51:31.025 [tid 19724] config: hook.Game::StrategyApp::RunAI=off
|
||||
09:51:31.025 [tid 19724] config: hook.Game::StrategyHost::Autosave=off
|
||||
09:51:31.025 [tid 19724] config: hook.Game::StrategyServer::ApplyEncounterResult=off
|
||||
09:51:31.025 [tid 19724] config: hook.Game::StrategyServer::BeginProcessTurn=off
|
||||
09:51:31.025 [tid 19724] config: hook.Game::StrategyServer::MoveFleet=off
|
||||
09:51:31.025 [tid 19724] config: hook.Game::StrategyServer::NodeLineDecay=off
|
||||
09:51:31.025 [tid 19724] config: hook.Game::StrategyServer::OnAllCombatDone_Tail=off
|
||||
09:51:31.025 [tid 19724] config: hook.Game::StrategyServer::ProcessFleetMovement=off
|
||||
09:51:31.025 [tid 19724] config: hook.Game::StrategyServer::ProcessNodeSpaceTravel=off
|
||||
09:51:31.025 [tid 19724] config: hook.Game::StrategyServer::ProcessTurn=off
|
||||
09:51:31.025 [tid 19724] config: hook.Game::WeaponDictionary::Init=off
|
||||
09:51:31.025 [tid 19724] config: hook.Mars::GlobalConsts::LoadFile=off
|
||||
09:51:31.025 [tid 19724] config: hook.Mars::RNG::Seed=off
|
||||
09:51:31.025 [tid 19724] config: hook.Game::TechTree::ProcessResearch=replace
|
||||
09:51:31.025 [tid 19724] config: research.replace_cascade=off
|
||||
09:51:31.025 [tid 19724] config: trace.path=C:\SOTS\shim.trace.jsonl
|
||||
09:51:31.025 [tid 19724] config: trace.inline_max=256
|
||||
09:51:31.025 [tid 19724] config: trace.flush=always
|
||||
09:51:31.088 [tid 19724] trace: C:\SOTS\shim.trace.jsonl (default mode trace, inline_max 256, flush always)
|
||||
09:51:31.088 [tid 19724] hook: Mars_Application_Initialize rva=0x004a0e50 -> va=013e0e50
|
||||
09:51:31.088 [tid 19724] hook: MH_Initialize -> MH_OK
|
||||
09:51:31.088 [tid 19724] hook: MH_CreateHook -> MH_OK (trampoline=017e0fe0)
|
||||
09:51:31.119 [tid 19724] hook: MH_EnableHook -> MH_OK
|
||||
09:51:31.119 [tid 19724] cfg: GlobalConsts hook ready (scale constant 0.017453292519943295)
|
||||
09:51:31.119 [tid 19724] hook: Mars::GlobalConsts::LoadFile rva=0x004b73c0 mode=off (not installed)
|
||||
09:51:31.119 [tid 19724] dict: dictionaries hook ready (crt new=73e7232b delete=73e70174)
|
||||
09:51:31.119 [tid 19724] hook: Game::WeaponDictionary::Init rva=0x0019a4c0 mode=off (not installed)
|
||||
09:51:31.119 [tid 19724] hook: Game::SectionDictionary::SectionDictionary rva=0x00176f40 mode=off (not installed)
|
||||
09:51:31.119 [tid 19724] research: ProcessResearch hook ready (Cost=010bda00, node=0x34, rng=0x9cc, fpu_cw=0x027f, replace_cascade=off)
|
||||
09:51:31.119 [tid 19724] hook: Game::TechTree::ProcessResearch rva=0x001876c0 -> va=010c76c0 MH_CreateHook -> MH_OK (trampoline=017e0fc0)
|
||||
09:51:31.134 [tid 19724] hook: Game::TechTree::ProcessResearch MH_EnableHook -> MH_OK mode=replace
|
||||
09:51:31.134 [tid 19724] techfx: OnTechResearched hook ready (regions=15, gate=0/0, fpu_cw=0x027f)
|
||||
09:51:31.134 [tid 19724] hook: Game::ServerPlayer::OnTechResearched rva=0x00491790 mode=off (not installed)
|
||||
09:51:31.134 [tid 19724] hook: Game::ServerPlayer::ComputeBudget rva=0x00463030 mode=off (not installed)
|
||||
09:51:31.134 [tid 19724] hook: Game::ServerSystem::ProcessTurn rva=0x003598e0 mode=off (not installed)
|
||||
09:51:31.134 [tid 19724] hook: Game::ServerSystem::GroupOutput rva=0x0034b7a0 mode=off (not installed)
|
||||
09:51:31.134 [tid 19724] hook: Game::ServerSystem::ComputeTotalOutput rva=0x00350480 mode=off (not installed)
|
||||
09:51:31.134 [tid 19724] player_turn: ServerPlayer::ProcessTurn hook armed (ratio helper at 010be950)
|
||||
09:51:31.134 [tid 19724] hook: Game::ServerPlayer::ProcessTurn rva=0x00491340 mode=off (not installed)
|
||||
09:51:31.134 [tid 19724] hook: Game::StrategyServer::MoveFleet rva=0x003d9ee0 mode=off (not installed)
|
||||
09:51:31.134 [tid 19724] hook: Game::StrategyServer::ProcessFleetMovement rva=0x003da9a0 mode=off (not installed)
|
||||
09:51:31.134 [tid 19724] hook: Game::StrategyHost::Autosave rva=0x00495210 mode=off (not installed)
|
||||
09:51:31.134 [tid 19724] hook: Game::StrategyServer::ProcessTurn rva=0x003dc6c0 mode=off (not installed)
|
||||
09:51:31.134 [tid 19724] hook: Game::StrategyServer::OnAllCombatDone_Tail rva=0x003d92a0 mode=off (not installed)
|
||||
09:51:31.134 [tid 19724] hook: Game::StrategyServer::ApplyEncounterResult rva=0x003d8920 mode=off (not installed)
|
||||
09:51:31.134 [tid 19724] hook: Game::StrategyServer::NodeLineDecay rva=0x003ae010 mode=off (not installed)
|
||||
09:51:31.134 [tid 19724] hook: Game::StrategyServer::ProcessNodeSpaceTravel rva=0x003a0e20 mode=off (not installed)
|
||||
09:51:31.134 [tid 19724] hook: Game::EncounterDetect::AssignContacts rva=0x003aa240 mode=off (not installed)
|
||||
09:51:31.134 [tid 19724] hook: Game::EncounterDetect::ProcessTeamRecord rva=0x003ca640 mode=off (not installed)
|
||||
09:51:31.134 [tid 19724] hook: Game::StrategyServer::BeginProcessTurn rva=0x003d98e0 mode=off (not installed)
|
||||
09:51:31.134 [tid 19724] hook: Game::SVSOSwarmQueen::OnTurnBegin rva=0x00129930 mode=off (not installed)
|
||||
09:51:31.134 [tid 19724] hook: Game::SVSOSwarmQueen::RegisterHives rva=0x00127630 mode=off (not installed)
|
||||
09:51:31.134 [tid 19724] hook: Game::SVSOSwarmQueen::TickHives rva=0x00127770 mode=off (not installed)
|
||||
09:51:31.134 [tid 19724] hook: Game::SVSOSlaversRefuel::UpdateDifficultyTier rva=0x00115820 mode=off (not installed)
|
||||
09:51:31.134 [tid 19724] hook: Mars::RNG::Seed rva=0x0009fdf0 mode=off (not installed)
|
||||
09:51:31.134 [tid 19724] hook: Game::StrategyApp::RunAI rva=0x004706f0 mode=off (not installed)
|
||||
09:51:31.166 [tid 19724] drawsite: Mars::RNG::NextFloat rva=0x0007d830 -> va=00fbd830 create=MH_OK enable=MH_OK
|
||||
09:51:31.181 [tid 19724] drawsite: Mars::RNG::NextInt rva=0x000271c0 -> va=00f671c0 create=MH_OK enable=MH_OK
|
||||
09:51:31.213 [tid 19724] drawsite: Mars::RNG::Chance rva=0x004e6dd0 -> va=01426dd0 create=MH_OK enable=MH_OK
|
||||
09:51:31.228 [tid 19724] drawsite: Mars::RNG::NextUInt rva=0x000f7670 -> va=01037670 create=MH_OK enable=MH_OK
|
||||
09:51:31.275 [tid 19724] drawsite: Mars::RNG::FloatRange rva=0x0007d8a0 -> va=00fbd8a0 create=MH_OK enable=MH_OK
|
||||
09:51:31.291 [tid 19724] drawsite: Mars::RNG::IntRangeBell rva=0x004e6d80 -> va=01426d80 create=MH_OK enable=MH_OK
|
||||
09:51:31.306 [tid 19724] drawsite: Mars::RNG::GaussianRange rva=0x004e6e30 -> va=01426e30 create=MH_OK enable=MH_OK
|
||||
09:51:31.306 [tid 19724] probe: installing 12 of 12 (probes= in shim.cfg)
|
||||
09:51:31.338 [tid 19724] probe: Game::ServerSpyManager::vslot13 rva=0x004877b0 -> va=013c77b0 create=MH_OK enable=MH_OK
|
||||
09:51:31.353 [tid 19724] probe: Game::ServerSpyManager::vslot14 rva=0x0048db80 -> va=013cdb80 create=MH_OK enable=MH_OK
|
||||
09:51:31.369 [tid 19724] probe: Game::ServerTradeManagerImpl::vslot13 rva=0x0048ef80 -> va=013cef80 create=MH_OK enable=MH_OK
|
||||
09:51:31.400 [tid 19724] probe: Game::ServerTradeManagerImpl::vslot15 rva=0x0042cca0 -> va=0136cca0 create=MH_OK enable=MH_OK
|
||||
09:51:31.416 [tid 19724] probe: Game::SpyManager::Slot13RngCallee rva=0x004408e0 -> va=013808e0 create=MH_OK enable=MH_OK
|
||||
09:51:31.431 [tid 19724] probe: Game::TradeManager::Slot13RngCalleeA rva=0x00420ca0 -> va=01360ca0 create=MH_OK enable=MH_OK
|
||||
09:51:31.463 [tid 19724] probe: Game::TradeManager::Slot13RngCalleeB rva=0x0048b440 -> va=013cb440 create=MH_OK enable=MH_OK
|
||||
09:51:31.478 [tid 19724] probe: Game::ServerTradeManager::CreateRaidEncounter rva=0x004938a0 -> va=013d38a0 create=MH_OK enable=MH_OK
|
||||
09:51:31.494 [tid 19724] probe: Game::ServerTradeManager::GenerateTradeRaidEncounters rva=0x00493290 -> va=013d3290 create=MH_OK enable=MH_OK
|
||||
09:51:31.525 [tid 19724] probe: Game::ServerSpyManager::vslot15 [control] rva=0x00487f30 -> va=013c7f30 create=MH_OK enable=MH_OK
|
||||
09:51:31.541 [tid 19724] probe: Game::ServerTradeManagerImpl::vslot14 [control] rva=0x004590d0 -> va=013990d0 create=MH_OK enable=MH_OK
|
||||
09:51:31.572 [tid 19724] probe: Game::EncounterDetect::Run [control] rva=0x003cb080 -> va=0130b080 create=MH_OK enable=MH_OK
|
||||
09:51:31.572 [tid 19724] watch: disabled (watch=off)
|
||||
09:51:31.572 [tid 19724] aiorders: disabled (aiorders=off)
|
||||
09:51:31.572 [tid 19724] fpu: module init, entry cw=0x027f 53bit-double/nearest; force=off value=0x0000 sample_ticks=on
|
||||
09:51:31.572 [tid 19724] fpu: sample_turn=on (off releases StrategyServer::ProcessTurn for another hook)
|
||||
09:51:31.572 [tid 19724] fpu: StrategyClient::EndTurn rva=0x00383be0 -> va=012c3be0 MH_CreateHook -> MH_OK (trampoline=017e0d40)
|
||||
09:51:31.588 [tid 19724] fpu: StrategyClient::EndTurn MH_EnableHook -> MH_OK
|
||||
09:51:31.588 [tid 19724] fpu: StrategyServer::BeginProcessTurn rva=0x003d98e0 -> va=013198e0 MH_CreateHook -> MH_OK (trampoline=017e0d20)
|
||||
09:51:31.619 [tid 19724] fpu: StrategyServer::BeginProcessTurn MH_EnableHook -> MH_OK
|
||||
09:51:31.619 [tid 19724] fpu: StrategyServer::ProcessTurn rva=0x003dc6c0 -> va=0131c6c0 MH_CreateHook -> MH_OK (trampoline=017e0d00)
|
||||
09:51:31.634 [tid 19724] fpu: StrategyServer::ProcessTurn MH_EnableHook -> MH_OK
|
||||
09:51:31.634 [tid 19724] fpu: DemoApp::OnTick rva=0x0049a640 -> va=013da640 MH_CreateHook -> MH_OK (trampoline=017e0ce0)
|
||||
09:51:31.666 [tid 19724] fpu: DemoApp::OnTick MH_EnableHook -> MH_OK
|
||||
09:51:31.666 [tid 19724] selftest: Shim::SelfTest::Fill mode=trace checksum=075ef0c3 records=1
|
||||
09:51:31.681 [tid 19724] Application::Initialize called (this=03938128)
|
||||
09:51:32.556 [tid 19724] fpu: TICK BASELINE at OnTick (this=03938128): cw=0x127f 53bit-double/nearest
|
||||
09:57:42.520 [tid 19724] fpu: sample at StrategyClient::EndTurn (this=0dc22d40): cw=0x127f 53bit-double/nearest [no fpu.force configured]
|
||||
09:57:45.614 [tid 19724] fpu: sample at StrategyClient::EndTurn (this=345fdee8): cw=0x127f 53bit-double/nearest [no fpu.force configured]
|
||||
09:57:45.645 [tid 19724] fpu: sample at StrategyClient::EndTurn (this=345fabf0): cw=0x127f 53bit-double/nearest [no fpu.force configured]
|
||||
09:57:45.692 [tid 19724] fpu: sample at StrategyClient::EndTurn (this=345fb338): cw=0x127f 53bit-double/nearest [no fpu.force configured]
|
||||
09:57:46.598 [tid 19724] fpu: sample at StrategyServer::BeginProcessTurn (this=0dc25ab8): cw=0x127f 53bit-double/nearest [no fpu.force configured]
|
||||
09:57:46.598 [tid 19724] fpu: sample at StrategyServer::ProcessTurn (this=0dc25ab8): cw=0x127f 53bit-double/nearest
|
||||
09:57:46.614 [tid 19724] research: mode=replace steps=1 completions=1 overbudget=1166 cascade_possible=0 ok=0 cascade_completions=0 unlocked=0 otch_appends=0 roll_draws=0 failures=0 depth=0 name_unreadable=0
|
||||
09:57:46.629 [tid 19724] research: mode=replace steps=1 completions=0 overbudget=0 cascade_possible=0 ok=0 cascade_completions=0 unlocked=0 otch_appends=0 roll_draws=0 failures=0 depth=0 name_unreadable=0
|
||||
09:57:46.629 [tid 19724] research: mode=replace steps=1 completions=0 overbudget=0 cascade_possible=0 ok=0 cascade_completions=0 unlocked=0 otch_appends=0 roll_draws=0 failures=0 depth=0 name_unreadable=0
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
09:42:14.649 [tid 19172] ==== sots-engine shim (binkw32 proxy) build cr-618ccb1-20260909T131556Z ====
|
||||
09:42:14.649 [tid 19172] exe: C:\SOTS\Sword of the Stars.exe
|
||||
09:42:14.649 [tid 19172] exe base=0x00f40000 (link-time image base 0x00400000, ASLR delta +11796480) pid=20592 shim=71d70000
|
||||
09:42:14.649 [tid 19172] addresses: Source: sots-re ghidra/addresses.json @ aa8d3fb, generated 2026-09-09 by tools/gen_addresses.py
|
||||
09:42:14.649 [tid 19172] config: hooks=trace
|
||||
09:42:14.649 [tid 19172] config: hook.Game::EncounterDetect::AssignContacts=off
|
||||
09:42:14.649 [tid 19172] config: hook.Game::EncounterDetect::ProcessTeamRecord=off
|
||||
09:42:14.649 [tid 19172] config: hook.Game::SVSOSlaversRefuel::UpdateDifficultyTier=off
|
||||
09:42:14.649 [tid 19172] config: hook.Game::SVSOSwarmQueen::OnTurnBegin=off
|
||||
09:42:14.649 [tid 19172] config: hook.Game::SVSOSwarmQueen::RegisterHives=off
|
||||
09:42:14.649 [tid 19172] config: hook.Game::SVSOSwarmQueen::TickHives=off
|
||||
09:42:14.649 [tid 19172] config: hook.Game::SectionDictionary::SectionDictionary=off
|
||||
09:42:14.649 [tid 19172] config: hook.Game::ServerPlayer::ComputeBudget=off
|
||||
09:42:14.649 [tid 19172] config: hook.Game::ServerPlayer::OnTechResearched=off
|
||||
09:42:14.649 [tid 19172] config: hook.Game::ServerPlayer::ProcessTurn=off
|
||||
09:42:14.649 [tid 19172] config: hook.Game::ServerSystem::ComputeTotalOutput=off
|
||||
09:42:14.649 [tid 19172] config: hook.Game::ServerSystem::GroupOutput=off
|
||||
09:42:14.649 [tid 19172] config: hook.Game::ServerSystem::ProcessTurn=off
|
||||
09:42:14.649 [tid 19172] config: hook.Game::StrategyApp::RunAI=off
|
||||
09:42:14.649 [tid 19172] config: hook.Game::StrategyHost::Autosave=off
|
||||
09:42:14.649 [tid 19172] config: hook.Game::StrategyServer::ApplyEncounterResult=off
|
||||
09:42:14.649 [tid 19172] config: hook.Game::StrategyServer::BeginProcessTurn=off
|
||||
09:42:14.649 [tid 19172] config: hook.Game::StrategyServer::MoveFleet=off
|
||||
09:42:14.649 [tid 19172] config: hook.Game::StrategyServer::NodeLineDecay=off
|
||||
09:42:14.649 [tid 19172] config: hook.Game::StrategyServer::OnAllCombatDone_Tail=off
|
||||
09:42:14.649 [tid 19172] config: hook.Game::StrategyServer::ProcessFleetMovement=off
|
||||
09:42:14.649 [tid 19172] config: hook.Game::StrategyServer::ProcessNodeSpaceTravel=off
|
||||
09:42:14.649 [tid 19172] config: hook.Game::StrategyServer::ProcessTurn=off
|
||||
09:42:14.649 [tid 19172] config: hook.Game::WeaponDictionary::Init=off
|
||||
09:42:14.649 [tid 19172] config: hook.Mars::GlobalConsts::LoadFile=off
|
||||
09:42:14.649 [tid 19172] config: hook.Mars::RNG::Seed=off
|
||||
09:42:14.649 [tid 19172] config: hook.Game::TechTree::ProcessResearch=replace
|
||||
09:42:14.649 [tid 19172] config: research.replace_cascade=on
|
||||
09:42:14.649 [tid 19172] config: trace.path=C:\SOTS\shim.trace.jsonl
|
||||
09:42:14.649 [tid 19172] config: trace.inline_max=256
|
||||
09:42:14.649 [tid 19172] config: trace.flush=always
|
||||
09:42:14.742 [tid 19172] trace: C:\SOTS\shim.trace.jsonl (default mode trace, inline_max 256, flush always)
|
||||
09:42:14.742 [tid 19172] hook: Mars_Application_Initialize rva=0x004a0e50 -> va=013e0e50
|
||||
09:42:14.742 [tid 19172] hook: MH_Initialize -> MH_OK
|
||||
09:42:14.742 [tid 19172] hook: MH_CreateHook -> MH_OK (trampoline=00cd0fe0)
|
||||
09:42:14.773 [tid 19172] hook: MH_EnableHook -> MH_OK
|
||||
09:42:14.773 [tid 19172] cfg: GlobalConsts hook ready (scale constant 0.017453292519943295)
|
||||
09:42:14.773 [tid 19172] hook: Mars::GlobalConsts::LoadFile rva=0x004b73c0 mode=off (not installed)
|
||||
09:42:14.773 [tid 19172] dict: dictionaries hook ready (crt new=73e7232b delete=73e70174)
|
||||
09:42:14.773 [tid 19172] hook: Game::WeaponDictionary::Init rva=0x0019a4c0 mode=off (not installed)
|
||||
09:42:14.773 [tid 19172] hook: Game::SectionDictionary::SectionDictionary rva=0x00176f40 mode=off (not installed)
|
||||
09:42:14.773 [tid 19172] research: ProcessResearch hook ready (Cost=010bda00, node=0x34, rng=0x9cc, fpu_cw=0x027f, replace_cascade=on)
|
||||
09:42:14.773 [tid 19172] hook: Game::TechTree::ProcessResearch rva=0x001876c0 -> va=010c76c0 MH_CreateHook -> MH_OK (trampoline=00cd0fc0)
|
||||
09:42:14.805 [tid 19172] hook: Game::TechTree::ProcessResearch MH_EnableHook -> MH_OK mode=replace
|
||||
09:42:14.805 [tid 19172] techfx: OnTechResearched hook ready (regions=15, gate=0/0, fpu_cw=0x027f)
|
||||
09:42:14.805 [tid 19172] hook: Game::ServerPlayer::OnTechResearched rva=0x00491790 mode=off (not installed)
|
||||
09:42:14.805 [tid 19172] hook: Game::ServerPlayer::ComputeBudget rva=0x00463030 mode=off (not installed)
|
||||
09:42:14.805 [tid 19172] hook: Game::ServerSystem::ProcessTurn rva=0x003598e0 mode=off (not installed)
|
||||
09:42:14.805 [tid 19172] hook: Game::ServerSystem::GroupOutput rva=0x0034b7a0 mode=off (not installed)
|
||||
09:42:14.805 [tid 19172] hook: Game::ServerSystem::ComputeTotalOutput rva=0x00350480 mode=off (not installed)
|
||||
09:42:14.805 [tid 19172] player_turn: ServerPlayer::ProcessTurn hook armed (ratio helper at 010be950)
|
||||
09:42:14.805 [tid 19172] hook: Game::ServerPlayer::ProcessTurn rva=0x00491340 mode=off (not installed)
|
||||
09:42:14.805 [tid 19172] hook: Game::StrategyServer::MoveFleet rva=0x003d9ee0 mode=off (not installed)
|
||||
09:42:14.805 [tid 19172] hook: Game::StrategyServer::ProcessFleetMovement rva=0x003da9a0 mode=off (not installed)
|
||||
09:42:14.805 [tid 19172] hook: Game::StrategyHost::Autosave rva=0x00495210 mode=off (not installed)
|
||||
09:42:14.805 [tid 19172] hook: Game::StrategyServer::ProcessTurn rva=0x003dc6c0 mode=off (not installed)
|
||||
09:42:14.805 [tid 19172] hook: Game::StrategyServer::OnAllCombatDone_Tail rva=0x003d92a0 mode=off (not installed)
|
||||
09:42:14.805 [tid 19172] hook: Game::StrategyServer::ApplyEncounterResult rva=0x003d8920 mode=off (not installed)
|
||||
09:42:14.805 [tid 19172] hook: Game::StrategyServer::NodeLineDecay rva=0x003ae010 mode=off (not installed)
|
||||
09:42:14.805 [tid 19172] hook: Game::StrategyServer::ProcessNodeSpaceTravel rva=0x003a0e20 mode=off (not installed)
|
||||
09:42:14.805 [tid 19172] hook: Game::EncounterDetect::AssignContacts rva=0x003aa240 mode=off (not installed)
|
||||
09:42:14.805 [tid 19172] hook: Game::EncounterDetect::ProcessTeamRecord rva=0x003ca640 mode=off (not installed)
|
||||
09:42:14.805 [tid 19172] hook: Game::StrategyServer::BeginProcessTurn rva=0x003d98e0 mode=off (not installed)
|
||||
09:42:14.805 [tid 19172] hook: Game::SVSOSwarmQueen::OnTurnBegin rva=0x00129930 mode=off (not installed)
|
||||
09:42:14.805 [tid 19172] hook: Game::SVSOSwarmQueen::RegisterHives rva=0x00127630 mode=off (not installed)
|
||||
09:42:14.805 [tid 19172] hook: Game::SVSOSwarmQueen::TickHives rva=0x00127770 mode=off (not installed)
|
||||
09:42:14.805 [tid 19172] hook: Game::SVSOSlaversRefuel::UpdateDifficultyTier rva=0x00115820 mode=off (not installed)
|
||||
09:42:14.805 [tid 19172] hook: Mars::RNG::Seed rva=0x0009fdf0 mode=off (not installed)
|
||||
09:42:14.805 [tid 19172] hook: Game::StrategyApp::RunAI rva=0x004706f0 mode=off (not installed)
|
||||
09:42:14.820 [tid 19172] drawsite: Mars::RNG::NextFloat rva=0x0007d830 -> va=00fbd830 create=MH_OK enable=MH_OK
|
||||
09:42:14.852 [tid 19172] drawsite: Mars::RNG::NextInt rva=0x000271c0 -> va=00f671c0 create=MH_OK enable=MH_OK
|
||||
09:42:14.867 [tid 19172] drawsite: Mars::RNG::Chance rva=0x004e6dd0 -> va=01426dd0 create=MH_OK enable=MH_OK
|
||||
09:42:14.883 [tid 19172] drawsite: Mars::RNG::NextUInt rva=0x000f7670 -> va=01037670 create=MH_OK enable=MH_OK
|
||||
09:42:14.916 [tid 19172] drawsite: Mars::RNG::FloatRange rva=0x0007d8a0 -> va=00fbd8a0 create=MH_OK enable=MH_OK
|
||||
09:42:14.945 [tid 19172] drawsite: Mars::RNG::IntRangeBell rva=0x004e6d80 -> va=01426d80 create=MH_OK enable=MH_OK
|
||||
09:42:14.961 [tid 19172] drawsite: Mars::RNG::GaussianRange rva=0x004e6e30 -> va=01426e30 create=MH_OK enable=MH_OK
|
||||
09:42:14.961 [tid 19172] probe: installing 12 of 12 (probes= in shim.cfg)
|
||||
09:42:14.992 [tid 19172] probe: Game::ServerSpyManager::vslot13 rva=0x004877b0 -> va=013c77b0 create=MH_OK enable=MH_OK
|
||||
09:42:15.008 [tid 19172] probe: Game::ServerSpyManager::vslot14 rva=0x0048db80 -> va=013cdb80 create=MH_OK enable=MH_OK
|
||||
09:42:15.039 [tid 19172] probe: Game::ServerTradeManagerImpl::vslot13 rva=0x0048ef80 -> va=013cef80 create=MH_OK enable=MH_OK
|
||||
09:42:15.070 [tid 19172] probe: Game::ServerTradeManagerImpl::vslot15 rva=0x0042cca0 -> va=0136cca0 create=MH_OK enable=MH_OK
|
||||
09:42:15.086 [tid 19172] probe: Game::SpyManager::Slot13RngCallee rva=0x004408e0 -> va=013808e0 create=MH_OK enable=MH_OK
|
||||
09:42:15.118 [tid 19172] probe: Game::TradeManager::Slot13RngCalleeA rva=0x00420ca0 -> va=01360ca0 create=MH_OK enable=MH_OK
|
||||
09:42:15.133 [tid 19172] probe: Game::TradeManager::Slot13RngCalleeB rva=0x0048b440 -> va=013cb440 create=MH_OK enable=MH_OK
|
||||
09:42:15.148 [tid 19172] probe: Game::ServerTradeManager::CreateRaidEncounter rva=0x004938a0 -> va=013d38a0 create=MH_OK enable=MH_OK
|
||||
09:42:15.180 [tid 19172] probe: Game::ServerTradeManager::GenerateTradeRaidEncounters rva=0x00493290 -> va=013d3290 create=MH_OK enable=MH_OK
|
||||
09:42:15.211 [tid 19172] probe: Game::ServerSpyManager::vslot15 [control] rva=0x00487f30 -> va=013c7f30 create=MH_OK enable=MH_OK
|
||||
09:42:15.226 [tid 19172] probe: Game::ServerTradeManagerImpl::vslot14 [control] rva=0x004590d0 -> va=013990d0 create=MH_OK enable=MH_OK
|
||||
09:42:15.258 [tid 19172] probe: Game::EncounterDetect::Run [control] rva=0x003cb080 -> va=0130b080 create=MH_OK enable=MH_OK
|
||||
09:42:15.258 [tid 19172] watch: disabled (watch=off)
|
||||
09:42:15.258 [tid 19172] aiorders: disabled (aiorders=off)
|
||||
09:42:15.258 [tid 19172] fpu: module init, entry cw=0x027f 53bit-double/nearest; force=off value=0x0000 sample_ticks=on
|
||||
09:42:15.258 [tid 19172] fpu: sample_turn=on (off releases StrategyServer::ProcessTurn for another hook)
|
||||
09:42:15.258 [tid 19172] fpu: StrategyClient::EndTurn rva=0x00383be0 -> va=012c3be0 MH_CreateHook -> MH_OK (trampoline=00cd0d40)
|
||||
09:42:15.273 [tid 19172] fpu: StrategyClient::EndTurn MH_EnableHook -> MH_OK
|
||||
09:42:15.273 [tid 19172] fpu: StrategyServer::BeginProcessTurn rva=0x003d98e0 -> va=013198e0 MH_CreateHook -> MH_OK (trampoline=00cd0d20)
|
||||
09:42:15.305 [tid 19172] fpu: StrategyServer::BeginProcessTurn MH_EnableHook -> MH_OK
|
||||
09:42:15.305 [tid 19172] fpu: StrategyServer::ProcessTurn rva=0x003dc6c0 -> va=0131c6c0 MH_CreateHook -> MH_OK (trampoline=00cd0d00)
|
||||
09:42:15.320 [tid 19172] fpu: StrategyServer::ProcessTurn MH_EnableHook -> MH_OK
|
||||
09:42:15.320 [tid 19172] fpu: DemoApp::OnTick rva=0x0049a640 -> va=013da640 MH_CreateHook -> MH_OK (trampoline=00cd0ce0)
|
||||
09:42:15.351 [tid 19172] fpu: DemoApp::OnTick MH_EnableHook -> MH_OK
|
||||
09:42:15.351 [tid 19172] selftest: Shim::SelfTest::Fill mode=trace checksum=075ef0c3 records=1
|
||||
09:42:15.367 [tid 19172] Application::Initialize called (this=03548128)
|
||||
09:42:16.336 [tid 19172] fpu: TICK BASELINE at OnTick (this=03548128): cw=0x127f 53bit-double/nearest
|
||||
09:48:17.041 [tid 19172] fpu: sample at StrategyClient::EndTurn (this=0d6dd1e0): cw=0x127f 53bit-double/nearest [no fpu.force configured]
|
||||
09:48:20.150 [tid 19172] fpu: sample at StrategyClient::EndTurn (this=32e7aed0): cw=0x127f 53bit-double/nearest [no fpu.force configured]
|
||||
09:48:20.181 [tid 19172] fpu: sample at StrategyClient::EndTurn (this=32e7f7a0): cw=0x127f 53bit-double/nearest [no fpu.force configured]
|
||||
09:48:20.228 [tid 19172] fpu: sample at StrategyClient::EndTurn (this=32e7a040): cw=0x127f 53bit-double/nearest [no fpu.force configured]
|
||||
09:48:21.134 [tid 19172] fpu: sample at StrategyServer::BeginProcessTurn (this=0d66ade8): cw=0x127f 53bit-double/nearest [no fpu.force configured]
|
||||
09:48:21.134 [tid 19172] fpu: sample at StrategyServer::ProcessTurn (this=0d66ade8): cw=0x127f 53bit-double/nearest
|
||||
09:48:21.150 [tid 19172] research: mode=replace steps=1 completions=1 overbudget=1166 cascade_possible=1 ok=1 cascade_completions=1 unlocked=3 otch_appends=1 roll_draws=0 failures=0 depth=0 name_unreadable=0
|
||||
09:48:21.181 [tid 19172] research: mode=replace steps=1 completions=0 overbudget=0 cascade_possible=1 ok=1 cascade_completions=0 unlocked=0 otch_appends=0 roll_draws=0 failures=0 depth=0 name_unreadable=0
|
||||
09:48:21.197 [tid 19172] research: mode=replace steps=1 completions=0 overbudget=0 cascade_possible=1 ok=1 cascade_completions=0 unlocked=0 otch_appends=0 roll_draws=0 failures=0 depth=0 name_unreadable=0
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Add table
Reference in a new issue