Compare commits
5 commits
77b5dd0d13
...
b6018a0f19
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b6018a0f19 | ||
|
|
c4ea347ace | ||
|
|
0d0b6dcfae | ||
|
|
fb5a4148b3 | ||
|
|
4b3cc82efb |
17 changed files with 5367 additions and 22 deletions
|
|
@ -1,17 +1,17 @@
|
||||||
# SotS RE campaign — coverage dashboard
|
# SotS RE campaign — coverage dashboard
|
||||||
|
|
||||||
Generated 2026-09-09 08:13 UTC · `sots-re` @ d46b3f8,2026-09-09 · `sots-engine` @ e7e2bd6,2026-09-09 (245 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
|
> **North star:** A functional reimplementation of the engine — behavior-equivalent, NOT byte-for-byte
|
||||||
|
|
||||||
## 1. Map coverage (campaign/board.md)
|
## 1. Map coverage (campaign/board.md)
|
||||||
|
|
||||||
444 targets · mapped-or-better **396/444** `[█████████░] 89%` · verified **354/444** `[████████░░] 80%`
|
447 targets · mapped-or-better **399/447** `[█████████░] 89%` · verified **356/447** `[████████░░] 80%`
|
||||||
|
|
||||||
| Status | Count | % |
|
| Status | Count | % |
|
||||||
|---|---:|---:|
|
|---|---:|---:|
|
||||||
| verified | 354 | 80% |
|
| verified | 356 | 80% |
|
||||||
| mapped | 42 | 9% |
|
| mapped | 43 | 10% |
|
||||||
| in-progress | 5 | 1% |
|
| in-progress | 5 | 1% |
|
||||||
| backlog | 41 | 9% |
|
| backlog | 41 | 9% |
|
||||||
| blocked | 2 | 0% |
|
| blocked | 2 | 0% |
|
||||||
|
|
@ -21,17 +21,17 @@ Generated 2026-09-09 08:13 UTC · `sots-re` @ d46b3f8,2026-09-09 · `sots-engine
|
||||||
| objects | 46 | 6 | 0 | 3 | 1 | 56 |
|
| objects | 46 | 6 | 0 | 3 | 1 | 56 |
|
||||||
| control-flow | 41 | 2 | 1 | 0 | 0 | 44 |
|
| control-flow | 41 | 2 | 1 | 0 | 0 | 44 |
|
||||||
| subsystems | 4 | 8 | 0 | 2 | 1 | 15 |
|
| subsystems | 4 | 8 | 0 | 2 | 1 | 15 |
|
||||||
| engine | 32 | 0 | 0 | 0 | 0 | 32 |
|
| engine | 33 | 1 | 0 | 0 | 0 | 34 |
|
||||||
| verify | 105 | 15 | 3 | 35 | 0 | 158 |
|
| verify | 105 | 15 | 3 | 35 | 0 | 158 |
|
||||||
| phase2 | 13 | 3 | 1 | 0 | 0 | 17 |
|
| phase2 | 13 | 3 | 1 | 0 | 0 | 17 |
|
||||||
| meta | 93 | 6 | 0 | 1 | 0 | 100 |
|
| meta | 94 | 6 | 0 | 1 | 0 | 101 |
|
||||||
| other | 20 | 2 | 0 | 0 | 0 | 22 |
|
| other | 20 | 2 | 0 | 0 | 0 | 22 |
|
||||||
|
|
||||||
## 2. Binary understanding
|
## 2. Binary understanding
|
||||||
|
|
||||||
- RTTI type descriptors: **1,924** (`Game::` 1,404, `Mars::` 194; serializable types 179)
|
- 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
|
- 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): **1294**, verified **1163** `[█████████░] 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
|
## 3. Data layer
|
||||||
|
|
||||||
|
|
@ -66,7 +66,7 @@ Generated 2026-09-09 08:13 UTC · `sots-re` @ d46b3f8,2026-09-09 · `sots-engine
|
||||||
| `shim/trace` | 2,258 | 9 | 273 | direct (WIN32) | shim-trace.md |
|
| `shim/trace` | 2,258 | 9 | 273 | direct (WIN32) | shim-trace.md |
|
||||||
| **total** | **59,514** | **122** | **4257** | | |
|
| **total** | **59,514** | **122** | **4257** | | |
|
||||||
|
|
||||||
Board `engine:` rows: verified **32**, mapped 0, in flight 0 (of 32) — verified & merged `[██████████] 100%`
|
Board `engine:` rows: verified **33**, mapped 1, in flight 0 (of 34) — verified & merged `[██████████] 97%`
|
||||||
|
|
||||||
## 5. Phase 2 milestones
|
## 5. Phase 2 milestones
|
||||||
|
|
||||||
|
|
@ -121,7 +121,7 @@ Detail: `verify/results/standalone/report.txt`.
|
||||||
|
|
||||||
## 8. Open questions
|
## 8. Open questions
|
||||||
|
|
||||||
Open **26** · resolved/parked 11 · backlog items: 1. The engine today 0, 2. The milestone, restated 5, 3. Engine work to Rung A 0, 4. Future engine modules 5, 5. Workloads to manufacture 7, 6. Multiplayer revival 4, 7. Method and infrastructure 5, Parked 2
|
Open **26** · resolved/parked 11 · backlog items: 1. The engine today 0, 2. The milestone, restated — 2026-09-09 7, 2-old. The milestone as restated 2026-09-08 5, 3. The plan — three tracks, in priority order 0, 4. Future engine modules 5, 5. Workloads to manufacture 7, 6. Multiplayer revival 4, 7. Method and infrastructure 5, Parked 2
|
||||||
|
|
||||||
Most recent open:
|
Most recent open:
|
||||||
|
|
||||||
|
|
@ -133,11 +133,11 @@ Most recent open:
|
||||||
|
|
||||||
## 9. Delta since previous dashboard
|
## 9. Delta since previous dashboard
|
||||||
|
|
||||||
- verified targets: 353 → 354 (+1) · mapped-or-better: 395 → 396 (+1)
|
- verified targets: 354 → 356 (+2) · mapped-or-better: 396 → 399 (+3)
|
||||||
- engine LOC: 59,504 → 59,514 (+10) · test files: 122 → 122 (+0) · checks: 4,257 → 4,257 (+0)
|
- engine LOC: 59,514 → 59,514 (+0) · test files: 122 → 122 (+0) · checks: 4,257 → 4,257 (+0)
|
||||||
- addresses verified: 1,163 → 1,163 (+0) · recovered layouts: 384 → 384 (+0) · open questions: 26 → 26 (+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)
|
- standalone leaves closed: 45 → 45 (+0) · leaves still diverging: 63 → 63 (+0)
|
||||||
|
|
||||||
---
|
---
|
||||||
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
|
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": 354, "mapped_plus": 396, "targets": 444, "loc": 59514, "tests": 122, "checks": 4257, "addr_verified": 1163, "addr_total": 1294, "layouts": 384, "open_q": 26, "sa_closed": 45, "sa_left": 63} -->
|
<!-- 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} -->
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,51 @@ run the economy/research/movement/output pieces to the original's numbers, and s
|
||||||
**16 of 44** driver phases and **5 of 37** tail phases modelled (10 committed). It cannot yet
|
**16 of 44** driver phases and **5 of 37** tail phases modelled (10 committed). It cannot yet
|
||||||
reproduce a turn.
|
reproduce a turn.
|
||||||
|
|
||||||
## 2. The milestone, restated (again — 2026-09-08 evening)
|
## 2. The milestone, restated — 2026-09-09 (after the determinism arc)
|
||||||
|
|
||||||
|
> `sots_turn` loads a save, runs one strategic turn, and writes an autosave that byte-matches
|
||||||
|
> the original's — **for a stated procedure and route**.
|
||||||
|
|
||||||
|
Two days of lanes went into determinism and the foundation is now laid. What is *measured*:
|
||||||
|
|
||||||
|
- **The sim is deterministic given the command stream.** Every draw of a turn attributed by
|
||||||
|
return address; the strategic generator's residual is 0 on every measured turn.
|
||||||
|
- **The AI is deterministic given (seeds, visit order).** Its per-process seed is one word per
|
||||||
|
client, minted from the global generator — which does *nothing else* on an encounter-free turn.
|
||||||
|
Pinning the seeds collapses a rich turn's divergence from 94 leaves to **one transposition**, and
|
||||||
|
that transposition is the **order of two heap pointers**: the fleet-assignment pass walks a
|
||||||
|
container keyed on `fleet->Location`. There is **no original order to match**; we choose one
|
||||||
|
member of its outcome set and say so (`orders.h`). The visit order is *written into the block*
|
||||||
|
(list 10), so a captured run carries its own.
|
||||||
|
- **The route is part of the procedure.** The same turn reached by continuation and by load gives
|
||||||
|
different, individually reproducible results, because a `Colonize` task alive in the AI agent by
|
||||||
|
continuation is *absent* after a load. Certified pairs live in `verify/results/saves/certified-pairs.md`
|
||||||
|
as `(save, procedure, route, hashes, processes, masks)`; a hash without its route is not a claim.
|
||||||
|
- **Exposure is a screen, not a decision procedure** (rule 26(c)): it says a control is *likely* to
|
||||||
|
vary; it cannot certify one will agree.
|
||||||
|
|
||||||
|
**So the rungs stand as written below, with one scope line each:**
|
||||||
|
|
||||||
|
- **Rung A** — byte-match modulo the command stream, **on a load→turn procedure**. Canonical pair
|
||||||
|
`ref-turn2 → turn3`. 204 leaves open; the RE for them is done (§3-old items 1b/1c/7).
|
||||||
|
- **Rung B** — byte-match given the recorded stream. **Climbed to outcome 3 on the first rich turn
|
||||||
|
(lane CV):** the replay runs and consumes the whole stream; the result is a **ranked leaf list of
|
||||||
|
thirteen named subsystems, zero ungrouped** — 1,092 leaves. Two blockers sit *upstream* of the
|
||||||
|
turn (§3, track 0). The tail's sim draw fires on this workload (`tscr = 253`), so Rung B needs
|
||||||
|
the same generator model as Rung A — that correction is load-bearing here.
|
||||||
|
- **Rung C** — `game/ai` deterministic given (save, seeds, visit order). **C-exact survives
|
||||||
|
literally** on that basis; the comparison side (`--relabel-new-ids`) ships with both acceptance
|
||||||
|
halves. The engine side is not built: `game/ai` mints no fleet ids yet.
|
||||||
|
|
||||||
|
**What stops now.** Further RNG/determinism lanes, unless a rung is actually blocked by one. Board
|
||||||
|
row count as a success signal — 89% of 444 rows measures campaign activity, not the product. The
|
||||||
|
value-domain census as a work generator — it is a screen; use it when a lane needs a corpus count.
|
||||||
|
|
||||||
|
**What the headline is.** Displacement (`tools/displacement.py`): **3 replaced / 7 compared /
|
||||||
|
7 modelled / 3 mapped**, unmoved for two days. And the phase catalogue: 14 of 44 driver phases,
|
||||||
|
2 of 37 tail. Those two numbers are the product.
|
||||||
|
|
||||||
|
## 2-old. The milestone as restated 2026-09-08 (kept for the record)
|
||||||
|
|
||||||
> `sots_turn` loads a save, runs one strategic turn, and writes an autosave that byte-matches
|
> `sots_turn` loads a save, runs one strategic turn, and writes an autosave that byte-matches
|
||||||
> the original's.
|
> the original's.
|
||||||
|
|
@ -87,7 +131,52 @@ candidate walk (lane L4) — the other two are stream-insensitive **by code path
|
||||||
Rung B is unaffected: `--turn-commands` replay stays the no-AI path, and the canonical pair stays
|
Rung B is unaffected: `--turn-commands` replay stays the no-AI path, and the canonical pair stays
|
||||||
`turn2-state → turn3-state` until the pin probe promotes the creation turn.
|
`turn2-state → turn3-state` until the pin probe promotes the creation turn.
|
||||||
|
|
||||||
## 3. Engine work to Rung A (ranked by leaves closed per lane)
|
## 3. The plan — three tracks, in priority order
|
||||||
|
|
||||||
|
### Track 0 — make the gate honest, then clear the two upstream blockers
|
||||||
|
|
||||||
|
The gate reported 59/59 for a day while the corpus tests **skipped** (`SOTS_SAVES_DIR` unset on
|
||||||
|
CT111). With the corpus it is **57/59**: the coverage ratchet broke when the corpus grew 22 → 43
|
||||||
|
(rule 27, as designed), and a writer defect appeared. `tools/gate.sh --fresh` is now the gate and
|
||||||
|
it fails if a corpus test skips.
|
||||||
|
|
||||||
|
| # | item | module | evidence | why first |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| 0a | **`ProjectName` reads `usnc` as one item; the wire is a `usp`/`usc` pair.** 12 of 43 saves round-trip 12 bytes short. | `mars/stream` | lane CV; `ad-turn27` has `usnc == 1` | no byte-match claim is possible on the `ad-*`/`ar-*` family until the writer is exact; re-prove byte-neutrality after |
|
||||||
|
| 0b | **Re-type what the ratchet caught** — the spy saves (`ap-*`) and whatever else dropped `pct` below 99.99. | `mars/stream` | `tools/gate.sh` output | the ratchet did its job; honour it |
|
||||||
|
| 0c | **List-5 applier cannot fire** because the memory capture cannot type 7 of 8 fields. One UI run (two sliders, two values) settles it. | shim capture | lane CV | the only list with an applier, at zero |
|
||||||
|
|
||||||
|
### Track 1 — displacement: `compared → replaced`, then `modelled → compared`
|
||||||
|
|
||||||
|
Only `replaced` means the original's code did not run. The bar, written once: an un-instrumented
|
||||||
|
oracle first (`certified-pairs.md` format), then the same procedure with the hook in `replace`
|
||||||
|
mode and the **same hashes**, with a count from the hook proving the path executed (rule 1).
|
||||||
|
|
||||||
|
| # | 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 | **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 |
|
||||||
|
|
||||||
|
### Track 2 — Rung B worklist, ranked against a real rich turn (lane CV, residual 0)
|
||||||
|
|
||||||
|
| leaves | subsystem | note |
|
||||||
|
|---:|---|---|
|
||||||
|
| 539 | morale event ring `cme2` | **not a module** — a fixed 11-slot ring shifted by 27 appended events of three kinds (colonisation, savings band, population). It is the reporting surface of the next three rows and closes when they do |
|
||||||
|
| 154 | colony growth / repair / bonuses | §3-old 1b/1c — `Pv*` is **mixed**: `PvPop`/`PvInfra` hold the uncapped projection, `PvSuit`/`PvRes` the pre-turn current |
|
||||||
|
| 150 | fleet objects | needs the gather/mint (Rung C engine side) |
|
||||||
|
| **79** | **`T34 RecordObservedDesigns`** | **largest independently closable stub, no upstream dependency — do this one first** |
|
||||||
|
| 30 | player money + counters | §3-old item 1 chain |
|
||||||
|
| 23 | `TShn` | watchpoint specified (§3-old 4) |
|
||||||
|
| 23 | system↔fleet membership | with fleet objects |
|
||||||
|
| 20 / 20 / 15 / 13 / 10 / 8 / 6 | ShipRecs · build queues · other system · crep/CD · id lists+generator · turnstats · trade manager | |
|
||||||
|
| 5 of 6 regressions | one `ntdev` predicate | cheapest fix in the list |
|
||||||
|
|
||||||
|
`ModCount` residual 2 is localised to lists 1/7/12; the only uniform reading is list 7 at 2 bumps —
|
||||||
|
a prediction fitted to one observation, falsified by any capture with a colonize count ≠ 2.
|
||||||
|
|
||||||
|
### §3-old — Rung A leaf ranking (still valid for the items it names)
|
||||||
|
|
||||||
| # | engine deliverable | module | RE input (done unless noted) | closes |
|
| # | engine deliverable | module | RE input (done unless noted) | closes |
|
||||||
|---|---|---|---|---|
|
|---|---|---|---|---|
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
256
findings/control-flow/raid-intercept-z-word.md
Normal file
256
findings/control-flow/raid-intercept-z-word.md
Normal file
|
|
@ -0,0 +1,256 @@
|
||||||
|
# `z` — the raid interception draw, measured
|
||||||
|
|
||||||
|
- **Type:** control-flow (static decode of the route-creation gate + live measurement of the draw)
|
||||||
|
- **Owner / date:** lane CZ · 2026-09-09 · guest **VM141** (`sots-re-win10-b`, 192.168.10.143)
|
||||||
|
- **Status:** *predictions committed; results below the line*
|
||||||
|
- **Decides:** the `z` term of lane AR's `k + s + z` tail model
|
||||||
|
(`raid-target-pick-verdict.md` §4.2), never observed through `Slot13RngCalleeB` by any lane;
|
||||||
|
and lane AZ's committed `k = 2` prediction on `az-turn23-tarka-comraid.sav`
|
||||||
|
(`raid-intercept-species-word.md` §3.3)
|
||||||
|
- **Instrument:** `draw_sites` at **`probes=8`** (`shim.cfg.hp8`, unmodified), shim build
|
||||||
|
`cz-e7e2bd6-dirty-20260909T1312Z`, built in `/srv/re-lab/build/sots-engine-cz` after an
|
||||||
|
`rm -rf` of the whole tree (rule 24), from lane worktree `~/sots-engine-cz` (branch `wip/cz`,
|
||||||
|
rule 21). **Never `probes=11`.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Predictions, committed before the guest was touched (rule 2)
|
||||||
|
|
||||||
|
*Everything in §1 was written and committed before the game was launched, before any order was
|
||||||
|
given and before any counter was read. It is not edited afterwards — only annotated with verdicts
|
||||||
|
below the line.*
|
||||||
|
|
||||||
|
### 1.0 The brief's Target 1 is impossible on this save, and the conjunct that kills it is decoded
|
||||||
|
|
||||||
|
My brief names the cheap workload as:
|
||||||
|
|
||||||
|
> Give player 0 a trade route sourced at `Ku'Paaka` (system index 17) or `Ka'Palum` (index 26) —
|
||||||
|
> both player-0 colonies and both members of sector 768, where the AI's `Rho Fleet` is already
|
||||||
|
> parked. **No fleet movement is required.**
|
||||||
|
|
||||||
|
**That state cannot be reached on `az-turn23-tarka-comraid.sav`, and not for want of patience.**
|
||||||
|
Rule 28 practice 2 says to decode the gate before building the state it names, so I read the route
|
||||||
|
rebuilder from the instruction stream on the host before launching anything.
|
||||||
|
|
||||||
|
`ServerTradeManagerImpl::vslot9` `0x00868060` (already named by lane V2) rebuilds the route vector
|
||||||
|
every turn. Per source endpoint it calls `0x008648e0`, and that function's **first** act after
|
||||||
|
initialising its scratch list is:
|
||||||
|
|
||||||
|
```
|
||||||
|
008648e0 TradeManager::BuildRoutesForSource(this, out, from, candidates)
|
||||||
|
0086494c call 0x8209e0 ; GetNumRoutesSupportedFrom(from, owner, true)
|
||||||
|
00864954 test eax,eax
|
||||||
|
00864956 jle 0x864b01 ; <<< <= 0 : NOTHING IS APPENDED, ever
|
||||||
|
...
|
||||||
|
00864991 call 0x83a690 ; per-candidate pair predicate
|
||||||
|
008649a4 call 0x8194a0 ; route already exists?
|
||||||
|
008649b7 ... operator_new(0x38), vtable 0x00a2d848 -> push_back a TradeRoute
|
||||||
|
```
|
||||||
|
|
||||||
|
and `TradeManager::GetNumRoutesSupportedFrom` `0x008209e0` returns **0** unless
|
||||||
|
|
||||||
|
```
|
||||||
|
008209e0 if (owner == 0) return 0
|
||||||
|
00820a20 sector = ((TradeSector**)this->+0x0c)[from->+0x4] ; the per-system containing-sector
|
||||||
|
if (sector == 0) return 0 ; table lane AR found
|
||||||
|
00820a2b if (owner->Species != 4) {
|
||||||
|
00820a3b if (!(sector->+0x88 & (1 << owner->+0x28))) return 0 ; <<< TSSEC
|
||||||
|
}
|
||||||
|
00820a58 if (from->+0x8 == 0) { ; a SYSTEM source
|
||||||
|
if (sys->PID != owner) return 0
|
||||||
|
return min(FUN_00819d20(sys), FUN_00819dd0(sys, ...))
|
||||||
|
}
|
||||||
|
... a STATION source: the global at 0x00af0c48
|
||||||
|
```
|
||||||
|
|
||||||
|
`TradeSector+0x88` is the serialised **`tssec`** (`objects/layouts.md`
|
||||||
|
`Game::ServerTradeSector`). So **a player can only source a trade route from a sector whose
|
||||||
|
`tssec` bit it holds** — and on `az-turn23-tarka-comraid.sav`, `tssec` reads
|
||||||
|
|
||||||
|
| `TradeID` | `tssec` | `tsct` | `tscr` |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 736 | **0** | 0 | 127 |
|
||||||
|
| 752 | **2** | 2 | 127 |
|
||||||
|
| **768** | **0** | 0 | 127 |
|
||||||
|
| 784 | **0** | 0 | 127 |
|
||||||
|
| 800 | **2** | 2 | 127 |
|
||||||
|
|
||||||
|
**Sector 768's `tssec` is 0 — for the AI as well as for me.** Player 0's bit is set in no sector
|
||||||
|
at all. So the route the brief asks me to create cannot be created, and no number of turns fixes
|
||||||
|
it by itself.
|
||||||
|
|
||||||
|
### 1.1 The three sector masks decoded, and verified against the save
|
||||||
|
|
||||||
|
Because a conjunct that blocks a briefed workload has to be more than an assertion, I decoded the
|
||||||
|
writer and checked it against every sector of every player in the save.
|
||||||
|
|
||||||
|
**`TradeSector::RecomputeStatusMasks` `0x0088df90` writes all three masks and their `p`-prefixed
|
||||||
|
previous copies** (`0x0088e031`–`0x0088e058` saves `tssec`/`tsct`/`tscr` into
|
||||||
|
`ptssec`/`ptsct`/`ptscr`):
|
||||||
|
|
||||||
|
| mask | offset | written at | value |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `tssec` | `+0x88` | `0x0088e0af` | bit `p` set iff `TradeSector_GetPlayerStatus(this, players[p]) == 0` |
|
||||||
|
| `tscr` | `+0x90` | `0x0088e733` | bit `p` set iff `players[p]->+0x100 != 0` — the **`CnRad`** bool |
|
||||||
|
| `tsct` | `+0x8c` | `0x0088e73c` | bit `p` set iff `players[p]->+0xff (CnTrd) != 0` **and** `tssec` bit `p` **and** a local mask OR'd from the triples `FUN_00864670` returns for this sector |
|
||||||
|
|
||||||
|
**`tscr` is a player-tech roster, not a sector property.** That closes lane AZ's open item, which
|
||||||
|
recorded the writer of `TradeSector+0x90` as unfound and refused to guess (`§3.2`,
|
||||||
|
`raid-intercept-species-word.md`). This save has **seven** players and **every one of them carries
|
||||||
|
`CnRad = True`**, so the mask is `0b1111111 = 127`. Lane AC's lineage has **eight** players with
|
||||||
|
exactly one `CnRad` false — the AI at index 1 — so the mask is `0b11111101 = 253`, and 252 is the
|
||||||
|
same roster one turn before the human's own Commerce Raiding completed. Three values, one rule, and
|
||||||
|
the "NPC slots default set" reading in `gate-indexed-rng-audit.md` §3.3 and `raid-gate-multiplicity.md`
|
||||||
|
§4 is retired: the NPC slots are set because **the NPC factions have the tech**, not because they
|
||||||
|
are NPCs.
|
||||||
|
|
||||||
|
**`TradeSector::GetPlayerStatus` `0x00819f00`** — twelve exits, decoded to the next function start:
|
||||||
|
|
||||||
|
```
|
||||||
|
if (p == 0) return 1
|
||||||
|
if (!p->+0xff) /* CnTrd */ return 5
|
||||||
|
members = this->+0x78..+0x7c
|
||||||
|
if (members.empty()) return 4
|
||||||
|
unexplored = friendly = hostile = 0
|
||||||
|
for (sys : members) {
|
||||||
|
if (sys->Dstyd || (sys->vnh && sys->vnex3)) continue ; 0x007469e0
|
||||||
|
if (sys->vnh) continue
|
||||||
|
if (!((sys->EFlags >> p->+0x28) & 1)) unexplored++ ; 0x00743880
|
||||||
|
owner = sys->PID
|
||||||
|
if (owner) {
|
||||||
|
if (sys->indi != 0 || !AtWar(p, owner)) friendly++ ; 0x00743fa0 / 0x0080ecb0
|
||||||
|
else hostile++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (unexplored > 0) return 4
|
||||||
|
if (friendly <= 0) return 2
|
||||||
|
return (hostile <= friendly) ? 0 : 3
|
||||||
|
```
|
||||||
|
|
||||||
|
`sys->+0xd0` is the serialised **`EFlags`**, `+0x100` is **`PID`**, `+0x1c8` is **`indi`**, and
|
||||||
|
`FUN_0080ecb0` is `a == b || PlayerAlliances_Relation(a, b) >= 1` — i.e. **not at war** — which
|
||||||
|
reuses lane T2's relation decode from the other side.
|
||||||
|
|
||||||
|
**Checked against the save, all five sectors and all seven players, and it reproduces exactly:**
|
||||||
|
|
||||||
|
| sector | predicted `tssec` | observed | player 0 status | AI (32) status |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| 736 | 0 | **0** | 4 (3 unexplored; friendly 3, hostile 0) | 4 (5 unexplored; friendly 0) |
|
||||||
|
| 752 | 2 | **2** | 4 (5 unexplored; **friendly 0, hostile 5**) | **0** (friendly 5, hostile 0) |
|
||||||
|
| 768 | 0 | **0** | 4 (5 unexplored; **friendly 3, hostile 9**) | 4 (2 unexplored) |
|
||||||
|
| 784 | 0 | **0** | 4 (3 unexplored; friendly 0, hostile 2) | 4 (1 unexplored) |
|
||||||
|
| 800 | 2 | **2** | 4 (2 unexplored; friendly 0, hostile 1) | **0** (friendly 1, hostile 0) |
|
||||||
|
|
||||||
|
Five sectors, seven players, thirty-five predicates, no disagreement.
|
||||||
|
|
||||||
|
**And it says exactly how dead Target 1 is.** In sector 768 player 0 holds **3** systems against the
|
||||||
|
AI's **9**. Even if I explored all five systems I have not surveyed there, `hostile (9) > friendly
|
||||||
|
(3)` returns **3**, not 0. The same arithmetic kills 752 (0 vs 5), 784 (0 vs 2) and 800 (0 vs 1).
|
||||||
|
**The only sector player 0 could ever qualify in is 736** — friendly 3, hostile 0, and only three
|
||||||
|
unexplored systems, all of them unowned and empty — and no AI fleet is parked at 736's node
|
||||||
|
(`tsnumflt = 0`). So the briefed "no fleet movement is required" route does not exist here, and the
|
||||||
|
cheapest state that reaches `z` is the one the brief lists as its **alternative**.
|
||||||
|
|
||||||
|
### 1.2 The workload I will actually build, named from the conjunct that survives
|
||||||
|
|
||||||
|
`G_B3` needs *a route owned by someone the raider is at war with*. Target 1 tried to satisfy it by
|
||||||
|
changing the **route**; I will satisfy it by changing the **raider**.
|
||||||
|
|
||||||
|
> **Park player 0's own Tarka raiders on the node of a sector that sources an AI route.**
|
||||||
|
|
||||||
|
Read from the save rather than inherited (the routes are `trfr = 4 → 9`, `trfr = 27 → 15`,
|
||||||
|
`trfr = 27 → 1`, all `tro = 32`, and `index = id/16 − 3` maps 4 to `Ke'Sothram` in sector **752** and
|
||||||
|
27 to `Keo'Va` in sector **800**):
|
||||||
|
|
||||||
|
| conjunct | how it is satisfied | evidence |
|
||||||
|
|---|---|---|
|
||||||
|
| G0–G2 fleet at a trade-sector node | order fleets to sector 752's node at `[0, 0, 8.0]` | AR's recipe |
|
||||||
|
| G3b raider's bit in `tscr` | `tscr = 127`, bit 0 set — player 0 has `CnRad = True` | §1.1 |
|
||||||
|
| G3c `FtFlg & 0x800` where armed | **not armed**: `tsct = 2` is the AI's bit, so `TradeSector_PlayerTradesHere(752, player 0)` is false | §1.1 |
|
||||||
|
| G4 `Pos` bit-equal | arrival at the node | AR §3.2 |
|
||||||
|
| `B` `flag` arm dead | `PlayerTradesHere` false ⇒ `FUN_0080ecf0` false ⇒ the diplomacy arm | AG §3.3 |
|
||||||
|
| G_B1b route sourced in this sector | `trfr = 4` lies in 752 | above |
|
||||||
|
| **G_B3 relation is 0 = war** | route owner is PID 32; player 0 and 32 both carry `AL = NA = CF = 0` | §1.4 |
|
||||||
|
| `SC1` route owner not Hiver | PID 32 is **species 2** | AZ §3.2 |
|
||||||
|
| `SC2` raider crew species not Hiver | player 0 is **species 2**, and `0x0081a2d0` returns the owner's species for a non-`_NPC` owner | AZ §1.2 |
|
||||||
|
| `SC3` `SpeciesDef[2]+0x144 == 0` | the flag word is written only for species 0 and 5 | AR §4.2 |
|
||||||
|
|
||||||
|
**Every conjunct is satisfied by a fleet move I control.** The build site is chosen from the save's
|
||||||
|
own geometry — distance from each player-0 system to sector 752's node, all three floats:
|
||||||
|
|
||||||
|
| player-0 system | idx | to 752's node | to 800's node |
|
||||||
|
|---|---|---|---|
|
||||||
|
| **`Ke'Rassak`** | **20** | **7.36** | 13.41 |
|
||||||
|
| `Kuo’Soro` | 16 | 9.85 | 15.08 |
|
||||||
|
| `Ku’Paaka` | 17 | 9.99 | 17.21 |
|
||||||
|
| `Kao’Thraal` | 0 | 12.31 | 17.33 |
|
||||||
|
| `Kea’Donum` | 3 | 13.16 | 17.15 |
|
||||||
|
| `Ka'Palum` | 26 | 13.93 | 18.24 |
|
||||||
|
|
||||||
|
A Tarka stock `Extended Range` destroyer has **Range 20.0** (lane AZ, from this game's own Build
|
||||||
|
screen), so **every one of the six is in range of 752's node** and five are in range of 800's.
|
||||||
|
Design `Extended Range` (`DesID 624`) is already in player 0's design list, and all six systems have
|
||||||
|
an **empty build queue**.
|
||||||
|
|
||||||
|
**The roll is per fleet, so I will build in several systems rather than splitting one stack.** A
|
||||||
|
fleet's odds are `0.05 + 0.01·nShips` for destroyers, doubled if a freighter shares the sector
|
||||||
|
(AC's read, undecided) — and **sector 752 holds the AI's `Freighters` fleet 3248**, so the doubling
|
||||||
|
is live here if it is live at all. Four two-ship fleets roll `4 × 0.07 = 0.28` per turn, or `0.56`
|
||||||
|
doubled; one eight-ship stack rolls `0.13`. Building two ships in each of four systems produces four
|
||||||
|
fleets **with no splitting at all**, which removes the right-click-menu step that cost lane AR time
|
||||||
|
and the staging error that cost lane AZ a 16-ship fleet.
|
||||||
|
|
||||||
|
**And I will not stage through a member system.** Lane AZ ordered a fleet to `Ku'Valt`, a sector-752
|
||||||
|
*member* system that is an AI colony, and lost sixteen destroyers to a real battle. The node is the
|
||||||
|
destination; nothing else is.
|
||||||
|
|
||||||
|
### 1.3 The numbered predictions
|
||||||
|
|
||||||
|
| # | prediction |
|
||||||
|
|---|---|
|
||||||
|
| **P0** | **`k = 2` on `az-turn23-tarka-comraid.sav` with the player owning no fleets** — lane AZ's committed prediction, taken as briefed. `Slot13RngCalleeA` is entered exactly **twice** on the first End Turn and `NextFloat 0x00820e18` reads `calls == words == 2`. The two are `Rho Fleet` (274, `LocID 768`, `FtFlg 0x80c`) and `Escorts` (3344, `LocID 752`, `FtFlg 0xc00`); `Freighters` 3248 and 4160 and `Nu Fleet IV` 1490 are rejected at G3c for lacking `FtFlg & 0x800` in a sector whose `tsct` bit is their owner's. Re-read from the save by this lane, not inherited |
|
||||||
|
| **P1** | **Neither AI raider can ever cost a word past `A`.** `Rho Fleet` stands on 768, which sources **no** route (`trfr ∈ {4, 27, 27}` lie in 752 and 800), so its `B` returns at **G_B4**. `Escorts` stands on 752, which sources one route — owned by its own player 32, so `PlayerAlliances_Relation` returns **3 for self**, `B` rejects at **G_B3** and the list empties, also G_B4. Two fleets, two different failed conjuncts, both at zero words |
|
||||||
|
| **P2** | **`tssec` gates route creation, and sector 768's is 0 for everyone**, so the briefed Target 1 is unreachable. Decoded at `0x00820a3b`; the mask's writer is `0x0088e0af`; the predicate is `TradeSector_GetPlayerStatus 0x00819f00`; and it reproduces all five sectors × seven players from the save (§1.1) |
|
||||||
|
| **P3** | **`tscr` is the `CnRad` roster.** Bit `p` is `players[p]->CnRad`, written at `0x0088e733`. 127 here (7 players, all true), 253 in the AC lineage (8 players, the AI false), 252 the turn before the human's tech landed. AZ's "the writer is unfound" is closed and the "NPC slots default set" reading is retired |
|
||||||
|
| **P4** | **`z` draws.** On the first turn one of my parked Tarka fleets succeeds, `draw_sites` shows **`NextFloat 0x00820c1b` `calls == words == 1`**, and the tail costs **`k + 2`** rather than `k + 1`. This is the first observation of that site through `Slot13RngCalleeB` in the campaign |
|
||||||
|
| **P5** | **The attribution is proved at the site, not at the bracket** (rule 23's corollary). A `0x00820c1b` row belongs to `B` on a turn where **`NextInt 0x008939ee` reads 0** — lane AZ's P6, whose static half is an image-wide `E8 rel32` scan finding exactly two callers of `FUN_00820af0`, with `0x0082cf65` reachable only through `CreateRaidEncounter`'s straight-line path past `0x008939ee`. If `0x008939ee` is non-zero on a turn I want to read, I will call that turn ambiguous and use another, not argue |
|
||||||
|
| **P6** | **The general model is `k + s + z` with `z = s`**, i.e. `OnAllCombatDone_Tail` costs **`k + 2s`** on this state, where `s` counts successes **by my fleets only** (P1 says the AI's two contribute nothing past `A`). Bracket residual **0** on every turn |
|
||||||
|
| **P7** | **`NextInt 0x0088b613` costs exactly one word per success.** Sector 752 sources one route, so `n = 1`, `bound = 0`, the mask smear gives 0 and `RNG_NextInt` cannot reject (AG §3.3, read in full). On sector 800, `n = 2`, `bound = 1`, mask 1, also exactly one. **If the AI's route set changes under me so that a target sector sources three or more, the rejection loop goes live and I will report `words > calls` rather than hide it** |
|
||||||
|
| **P8** | **A success displaces the raider off the node** (`fleet->Pos = out` at `0x0088b672`, AR §4.3), so `k` **falls by one** on the turn after each of my successes, and each fleet contributes at most one success per parking. The same applies to the AI's `Escorts` on 752 — if it succeeds, `k` drops to 1 + mine even before I arrive |
|
||||||
|
| **P9** | **The `hooks=off` control will NOT agree with itself.** Rule 26 corollary (c)'s screen fires: `Player[32]` (`Fane Kona`, `PlyrIdx 1`, `NumOwn 17`, `NumDes 58`, an AI player that runs) enters the turn with **`ResTNm == ''`**, which is a research-pick turn. I expect variation confined to `Player[32]`'s `TechTree` leaves and the derived `/Summary/Checksum`, and I expect **`/Sim/trdmgr`, the five `Trade` records and `/Sim/fleets` to be sub-tree identical** across processes — which would leave `k`, the route set and the raid arm reproducible even though the whole-save hash is not. **I am predicting the sub-trees my measurement depends on, in advance, so that "the control varied" cannot be turned into "the measurement is fine" after the fact.** Note (c)'s own restatement: `ResTNm == ''` predicts that a pick is *made*, not that it *varies*, so an agreeing control would not surprise me either |
|
||||||
|
| **P10** | **The AI-client roster is `{32, 496, 512}`** — three clients out of six non-human players — by lane BP's rule that the NPC factions at net ids 528 and above get no client. `528 Peacekeeper Enforcer`, `544 Von Neumann` and `560 Independent Colony` carry `ResTNm == ''` **and** `NumOwn == 0` **and** no client, so their signature is inert. **This is an inference from another save and I will label it as one unless I measure it** with an `aiseed=log` process |
|
||||||
|
| **P11** | **Not settled by this lane, predicted in advance** (rule 15): the freighter doubling of the raid odds (one or two successes cannot separate 0.07 from 0.14); `design+0x12c > 1`; `bestScale`; the `0x0088b613` rejection loop at `n >= 3`; whether `SC2` (a Hiver raider) is reachable at all; and the leaf semantics of `FUN_00819d20` / `FUN_00819dd0`, the two route-count sources `GetNumRoutesSupportedFrom` takes the `min` of |
|
||||||
|
|
||||||
|
### 1.4 The falsifier, stated as the sentence I will have to write
|
||||||
|
|
||||||
|
> **If one of my parked Tarka fleets succeeds — `Slot13RngCalleeB` is entered, `NextInt 0x0088b613`
|
||||||
|
> fires for one word, `0x008939ee` reads 0 — and there is still no `NextFloat 0x00820c1b` row,
|
||||||
|
> then `SpeciesDef+0x144` is not the whole gate**, and the two short-circuits ahead of it become
|
||||||
|
> the live suspects: `owner->+0x5c == 1` on the route owner (checkable in the save: PID 32 carries
|
||||||
|
> `Species 2`) and `FUN_0081a2d0(fleet) == 1` on the raider's crew species (checkable the same way:
|
||||||
|
> player 0 carries `Species 2`). If both check out, the static decode that three lanes have now
|
||||||
|
> read the same way is retired, and the interesting question becomes what `0x0053baf0` actually
|
||||||
|
> reads.
|
||||||
|
|
||||||
|
And the other direction, which is the more likely negative:
|
||||||
|
|
||||||
|
> **If `Slot13RngCalleeB` is never entered with a non-empty candidate list**, I will report *which*
|
||||||
|
> conjunct failed by reading it out of the turn's own autosave — `LocID`, all three floats of `Pos`
|
||||||
|
> against the sector's, `FtFlg`, the sector's `tsct`/`tscr`, and the live `trfr` set — and not as
|
||||||
|
> "the species word did not fire". A negative without a named conjunct is "not reached in the states
|
||||||
|
> measured", which is a different sentence (rule 28 practice 1).
|
||||||
|
|
||||||
|
### 1.5 What could go wrong with the workload, and the symptom of each
|
||||||
|
|
||||||
|
| way it fails | symptom |
|
||||||
|
|---|---|
|
||||||
|
| the AI's route set moves and 752 stops sourcing a route | `trfr` in the per-turn autosave no longer contains 4; `B` entered, 0 words, G_B4 — mitigated by also sending fleets to 800's node |
|
||||||
|
| a sector I target starts sourcing three or more routes | `0x0088b613` `words > calls`; reported, not hidden (P7) |
|
||||||
|
| the node cannot be aimed at from the default camera | AZ's §6: the Move-mode hover snaps to the nearest **system** over >100 px. Sector 752's node is 2.4 ly from `Ke'Sothram`. **`rdrag` rotates the star map** — rotate first, then aim, and confirm from the hover readout (`Sector 2 / Range / ETA`) before committing |
|
||||||
|
| a fleet is intercepted in transit | it dies; the arm shrinks. Fleets are ordered **to the node**, never through a member system (AZ's §6 cause 1) |
|
||||||
|
| an encounter query blocks a scripted End Turn | the driver polls the **autosave mtime**, never a button colour, and **stalls with a screenshot** rather than clicking blind. AZ lost a 16-ship fleet to a blind `Auto Resolve Peacefully` sequence, and `Auto Resolve Peacefully` means "I commit no ships", not "no combat occurs" |
|
||||||
|
| the control varies | expected (P9). Localise by sub-tree with `state_checksum.py --tree` and state which leaves the measurement depends on |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Results, and the verdicts, follow below. Nothing above this line is edited after the run.*
|
||||||
251
findings/subsystems/research-replace.md
Normal file
251
findings/subsystems/research-replace.md
Normal file
|
|
@ -0,0 +1,251 @@
|
||||||
|
# Taking `TechTree::ProcessResearch` + the unlock cascade from `compare` to `replace` (lane CR)
|
||||||
|
|
||||||
|
**Lane CR, 2026-09-09. Guest: VM145 (`sots-re-win10-145`, `re@192.168.10.145`) — held by this lane.**
|
||||||
|
VM140 is untouched (it is the exclusive reference guest).
|
||||||
|
|
||||||
|
The board's headline metric is `tools/displacement.py`: **3 replaced / 7 compared / 7 modelled /
|
||||||
|
3 mapped**. `TechTree::ProcessResearch + unlock cascade` is the best-evidenced `compared` row — 35
|
||||||
|
calls, three workloads, 0 divergences, `tracecmp` exit 0, and an advance prediction that held on a
|
||||||
|
*changed* workload. This lane asks the only question that moves the metric: **can our code run
|
||||||
|
INSTEAD of the original's, live, with a byte-level oracle holding afterwards?**
|
||||||
|
|
||||||
|
Everything above the `## 4.` heading was committed **before** the shim was built or staged
|
||||||
|
(rule 2). Nothing above that line is edited afterwards; corrections are made below it and named as
|
||||||
|
corrections (rule 11).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. The state, and why this one
|
||||||
|
|
||||||
|
### 1.1 The candidate the brief names, and why it is not sufficient on its own
|
||||||
|
|
||||||
|
`ref-turn2.sav` (`ab4ac2d7…`, = `verify/results/saves/turn2-state.sav`) is the campaign's oldest and
|
||||||
|
most reproduced oracle: one End Turn by the **load** route, `(Autosave EndTurn)` `bb4fd9ac…` /
|
||||||
|
`(Autosave)` `978041ac…`, **5 + 1 processes**, certified-pairs row 1.
|
||||||
|
|
||||||
|
**It does not exercise a research completion.** This is not an inference from the exit code — it is
|
||||||
|
read off lane U's own instruments, both of which are in this repo:
|
||||||
|
|
||||||
|
* `verify/results/compare/unlock-b3-t1.md`: 3 calls, 3 compared, 0 diverged, and
|
||||||
|
**`0 undeclared write(s) in 0 call(s)`**. Every completion in every measured run produces
|
||||||
|
undeclared writes on the `player` and `tree_header` guards, because that is where
|
||||||
|
`OnTechResearched`'s tech effects and the tree's order counter land. Zero undeclared writes is
|
||||||
|
zero completions.
|
||||||
|
* `verify/results/shim/unlock-shim.log`: the first three `research: cascade ok=1 …` lines of the
|
||||||
|
five-turn continuation read `completions=0 unlocked=0 otch_appends=0`. Those three lines *are*
|
||||||
|
the `ref-turn2` End Turn.
|
||||||
|
|
||||||
|
Reading the trace rather than the verdict (rule 1) says what that turn *does* do: call 0 advances
|
||||||
|
the generator by one word (`left` 432 → 431), pushes node 144's progress 2879 → 5768, sets its flag
|
||||||
|
1 → 2 (`OverBudgetNotified`) and posts one event (`next_id` 3 → 4). Calls 1 and 2 change **nothing
|
||||||
|
at all**. So `ref-turn2` + one End Turn is a real workload for the *pass* and an empty one for the
|
||||||
|
*completion path*. **A replace-mode oracle taken there would be exactly the green verdict on a hook
|
||||||
|
that compared nothing that rule 1 exists to catch.**
|
||||||
|
|
||||||
|
### 1.2 The state this lane uses
|
||||||
|
|
||||||
|
**`verify/results/saves/turn3-state.sav`** — 67,219 B, sha256
|
||||||
|
`978041acd168b56ed8eb3f5e42e78d5e70eae6e6517d75e659a5eb7ca3d60921`, `Summary.Turn = 3`,
|
||||||
|
`Sim.ModCount = 24`. It is *the output of certified-pairs row 1*: the `(Autosave).sav` that
|
||||||
|
`ref-turn2` + one End Turn produces. It is already on VM145 under that hash as `(Autosave).sav`.
|
||||||
|
|
||||||
|
**Procedure: one End Turn. Route: LOAD.** Stated because the route is part of the pair
|
||||||
|
(rule 26(c) fourth term; lane BS): the same turn reached by continuation and by load is two
|
||||||
|
different, individually reproducible things, and this lane deliberately does **not** inherit the
|
||||||
|
continuation's turn-4 numbers as an assumption — it predicts them and lets the load route falsify
|
||||||
|
them (P1).
|
||||||
|
|
||||||
|
Why this turn: in lane U's five-turn continuation the **fourth-turn** call is the completing one.
|
||||||
|
The call that enters with `turn = 4` allocates 2,898 points to tech 144, completes it, and runs the
|
||||||
|
cascade — `completions=1 unlocked=3 otch_appends=1` in the shim log, `next_id` 5 → 7 and
|
||||||
|
`observed_techs` 440 → 484 bytes in the trace. `turn3-state.sav` is the state that turn starts from.
|
||||||
|
|
||||||
|
### 1.3 The exposure screen (rule 26(c)) — a screen, not a decision procedure
|
||||||
|
|
||||||
|
Read from `turn3-state.sav` with `verify/save-reader/save_reader.py`. Eight players; per lane BP the
|
||||||
|
engine builds AI clients for net ids **32, 496, 512** only, and the four factions at 528–576 carry
|
||||||
|
their signature **inertly**.
|
||||||
|
|
||||||
|
| player | species | `ResTNm` | `Status` | AI client | pick-turn signature? |
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| 16 (human `re`) | 0 | `''` | 4 | **no** (local human) | **false positive** — no client |
|
||||||
|
| 32 | 2 | `IND_Waldo` | 4 | yes | **no** — mid-research |
|
||||||
|
| 496 | 0 | `DRV_PlsFiss` | 4 | yes | **no** — mid-research |
|
||||||
|
| 512 | 2 | `BIO_GnMod` | 4 | yes | **no** — mid-research |
|
||||||
|
| 528, 544, 560, 576 | 4 | `''` | 0 | **no** | **false positive** — no client, `Status 0` |
|
||||||
|
|
||||||
|
**No player that actually runs enters this turn with an empty research target.** That is the best
|
||||||
|
the screen can say. It cannot say the control will agree — rule 26(c)'s own retraction is explicit
|
||||||
|
that `candidatesTried` is not readable from a save, that there is a combat term, and that the load
|
||||||
|
route is a fourth term that is not a predicate on the save at all. **So the screen is why this turn
|
||||||
|
is worth trying, and the two-process control in §4.1 is the only thing that decides it.**
|
||||||
|
|
||||||
|
The lineage where exposure is saturated (`ad-…`/`ar-…`, every turn carrying a signature) is
|
||||||
|
deliberately not used here.
|
||||||
|
|
||||||
|
### 1.4 What is being asked of `hooks=off`
|
||||||
|
|
||||||
|
Three fresh-process runs are planned before any replace result is read:
|
||||||
|
|
||||||
|
| run | config | what it establishes |
|
||||||
|
|---|---|---|
|
||||||
|
| **C1**, **C2** | `shim.cfg.croff` (`hooks=off`, the proxy loads and installs nothing) | the control agrees with itself across two fresh processes (rule 26) |
|
||||||
|
| **N** | `shim.cfg.crcompare` (one detour, `compare`) | the instrument is behaviour-neutral on *this* save and route (rule 19), **and** it is where the completion count comes from the hook itself |
|
||||||
|
|
||||||
|
Only then the replace runs. C1/C2 use the *same proxy DLL* as every measured run, so the only
|
||||||
|
difference between control and measurement is the config (lane CB's shape).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. The four bytes of every float literal on this path (rule 23)
|
||||||
|
|
||||||
|
Two float literals are on the research pass's arithmetic path, and **both are widened `float`s**.
|
||||||
|
Read here directly out of `dumps/sots.exe` (PE image base `0x00400000`, `.rdata` at `0x009dd000`
|
||||||
|
file offset `0x5dbe00`), not taken from an earlier note:
|
||||||
|
|
||||||
|
| VA | bytes (LE) | value as `double` | is it `(double)float`? | engine constant |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| `0x009e20c8` | `00 00 00 a0 99 99 e9 3f` | `0.80000001192092896` | **yes** (low 29 bits zero) | `kEarlyCompletionRatio = 0.800000011920929` |
|
||||||
|
| `0x009e5060` | `00 00 00 a0 99 99 a9 3f` | `0.05000000074505806` | **yes** | `kDecayFraction = 0.05000000074505806` |
|
||||||
|
|
||||||
|
Both source literals were re-parsed and re-packed: `0.800000011920929` → `000000a09999e93f` and
|
||||||
|
`0.05000000074505806` → `000000a09999a93f`. **Bit-identical to the image.** So the two constants
|
||||||
|
`sots-engine/src/game/sim/research.cpp` relies on are exactly the image's, not the exact decimals
|
||||||
|
that bit the money chain twice.
|
||||||
|
|
||||||
|
Two literals that are **not** on this path, and why:
|
||||||
|
|
||||||
|
* the tech-cost multiplier (`1.0 − 0.25·n`, floor `0.25`) — `ours` never evaluates it. It calls the
|
||||||
|
game's own read-only `TechTree::Cost` for every cost it needs, in both modes (`g_env.cost`). This
|
||||||
|
is a genuine, declared dependency on the original: the effective cost is **not** displaced.
|
||||||
|
* `ResearchSpendFloor` / `Ceiling` are integer `×50/100` and `×150/100` with a 32-bit wrapping
|
||||||
|
multiply — no float involved.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Predictions, committed before the build
|
||||||
|
|
||||||
|
Falsification symptoms are given for each. Predictions are made **per site** and not at a bracket
|
||||||
|
total (rule 23's 2026-09-09 corollary).
|
||||||
|
|
||||||
|
### P0 — the control agrees with itself
|
||||||
|
`turn3-state.sav`, one End Turn, load route, `hooks=off`, **two fresh processes** produce identical
|
||||||
|
`(Autosave EndTurn).sav` and `(Autosave).sav`.
|
||||||
|
*Falsified if:* the two processes differ. Then this workload is exposed, the screen in §1.3 was
|
||||||
|
insufficient (which is what rule 26(c)'s retraction predicts is possible), and the honest move is to
|
||||||
|
report that and pin the source of variation — **not** to pick the run that suits.
|
||||||
|
|
||||||
|
### P1 — the turn is not quiet, and the load route reproduces the continuation's turn-4 call
|
||||||
|
Exactly **3** `ProcessResearch` calls, one per AI client, in the same owner order. Allocations:
|
||||||
|
**A → {tech 144, 2898 points}**, **B → {tech 90, 0 points}**, **C → {tech 9, 0 points}**. Exactly
|
||||||
|
**one completion** (tech 144) and the cascade unlocks exactly **three** nodes:
|
||||||
|
|
||||||
|
| node | `state` | `cost_rp` | `turn_available` |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 132 | 0 → 2 | `INT_MAX` → **10000** | −1 → **4** |
|
||||||
|
| 136 | 0 → 2 | `INT_MAX` → **16000** | −1 → **4** |
|
||||||
|
| 142 | 0 → 2 | `INT_MAX` → **8000** | −1 → **4** |
|
||||||
|
|
||||||
|
*Falsified if:* a different allocation, a different completion count, or a different unlock set. That
|
||||||
|
would be a **route** result — the load route not reproducing the continuation — and it is worth as
|
||||||
|
much as the replace result. It is exactly what rule 26(c)'s fourth term says can happen.
|
||||||
|
|
||||||
|
### P2 — the arithmetic, hand-computed on the boundary
|
||||||
|
For node 144: `cost = 5000`, `lo = ResearchSpendFloor = 2500`, `hi = ResearchSpendCeiling = 7500`.
|
||||||
|
Entering progress **5768**, allocation **2898**:
|
||||||
|
|
||||||
|
* `spent = min(2898, 7500 − 5768) = 1732` — the cap binds, so this call lands **exactly on the
|
||||||
|
ceiling**, which is the boundary rule 23 says to test by hand rather than trust a compare on.
|
||||||
|
* `progress 5768 → 7500`, `overbudget 0 → 1166`.
|
||||||
|
* `progress (7500) < hi (7500)` is **false**, so the odds/roll branch is skipped: **zero RNG draws**.
|
||||||
|
I predict `rng.left` is **unchanged at 413** across all three calls and the `mt` digest does not
|
||||||
|
move on any of them.
|
||||||
|
* `ratio = (float)(7500/5000) = 1.5`, and `1.5 < 0.800000011920929` is false → **not** completed
|
||||||
|
early → `flag` **unchanged**.
|
||||||
|
* `state 3 → 4`, `turn_researched −1 → 4`, `order −1 → 22`, and the tree's order counter
|
||||||
|
`22 → 23`.
|
||||||
|
|
||||||
|
*Falsified if:* any single one of these moves. A wrong `hi` shows up as a wrong `overbudget`; a
|
||||||
|
wrong early-completion literal shows up as `flag` moving.
|
||||||
|
|
||||||
|
### P3 — the instrument is neutral, and the completion is counted by the instrument
|
||||||
|
Run N (`crcompare`, one detour) produces autosaves **byte-identical to C1/C2**, and `tracecmp`
|
||||||
|
reports **3 calls / 3 compared / 0 diverged / exit 0**. The hook's own per-call log line reads
|
||||||
|
`completions=1 … unlocked=3 otch_appends=1` on the completing call and all-zero on the other two.
|
||||||
|
Undeclared writes: **6 spans in 1 call** —
|
||||||
|
`player +0x10c/3`, `player +0x110/3`, `player +0x114/3`, `player +0x124/3`, `player +0x294/4`
|
||||||
|
(`ResT`, the research target being cleared) and `tree_header +0x20/1` (the order counter).
|
||||||
|
|
||||||
|
*Falsified if:* the autosaves move (then rule 19 bites and nothing below is readable), or the
|
||||||
|
undeclared-write set differs (then the workload or the model moved).
|
||||||
|
|
||||||
|
### P4 — replace with the cascade OFF (`crreplace0`, the shipped behaviour) diverges
|
||||||
|
The autosave is **not** byte-identical. Predicted diverging leaves, by name:
|
||||||
|
|
||||||
|
1. `Player[32]` tech tree: node 144 `turn_researched` and `order` unstamped (−1/−1); nodes 132, 136
|
||||||
|
and 142 unchanged at `state 0`, `cost_rp INT_MAX`, `turn_available −1`.
|
||||||
|
2. the tree's completion-order counter left at 22.
|
||||||
|
3. `Player[32]` events: `next_id` short by **2**, two event records absent.
|
||||||
|
4. `Player[32]` `otch`: one `ObservedTech` element absent (**44 bytes**).
|
||||||
|
5. `Player[32]` scalar fields at `+0x10c`, `+0x110`, `+0x114`, `+0x124` unchanged, and `ResTNm` still
|
||||||
|
reading `IND_Waldo` because `ResT` was never cleared.
|
||||||
|
|
||||||
|
What **will** be right even here: node 144's `state = 4`, `progress = 7500`, `flag`, the decay sweep
|
||||||
|
over every other node, and the `overbudget` accumulator.
|
||||||
|
|
||||||
|
### P5 — replace with the cascade ON (`crreplace1`) diverges, by strictly less
|
||||||
|
Same binary, one config line different (`research.replace_cascade=on`; see §3.1). Predicted:
|
||||||
|
**strictly fewer diverging leaves than P4**, with items 1 and 2 of P4 **closed** — node 144 stamped
|
||||||
|
`turn_researched 4` / `order 22`, nodes 132/136/142 at `state 2` with `cost_rp` 10000/16000/8000 and
|
||||||
|
`turn_available 4`, counter at 23 — and items 3, 4 and 5 **still open**.
|
||||||
|
|
||||||
|
### P6 — the headline, stated in advance
|
||||||
|
**`game/sim/research` does NOT move from `compared` to `replaced` this session, and the named cause
|
||||||
|
is `ServerPlayer::OnTechResearched`, not the research model.** The research pass itself — the spend
|
||||||
|
cap, the odds branch, the completion, the decay sweep, and (with the flag on) the whole
|
||||||
|
`SetResearched` cascade — is displaceable and I expect it to reproduce the original's TechTree state
|
||||||
|
exactly. What blocks the oracle is the *callback*: it posts events whose text comes from the game's
|
||||||
|
string table, appends an `ObservedTech` element `ours` decides but does not construct, and writes
|
||||||
|
~90 `ServerPlayer` fields that are a different subsystem's milestone (B2) and a separate `compared`
|
||||||
|
row on the board. A replace of the research pass is **gated on displacing `OnTechResearched`**, and
|
||||||
|
that is a statement about a boundary, not about the research model.
|
||||||
|
|
||||||
|
*Falsified if:* `crreplace1`'s autosave is byte-identical to the oracle. That would mean the
|
||||||
|
callback's writes do not reach the save on this workload, P6 is wrong, and the row moves to
|
||||||
|
`replaced` — which is the outcome I would rather have and do not expect.
|
||||||
|
|
||||||
|
### P7 — the numbers I expect to be able to quote honestly afterwards
|
||||||
|
**1** distinct completion, **1** distinct tech (144), **3** unlocked nodes, **3** calls of which
|
||||||
|
**2** allocate zero points and write nothing at all. That is thin, and it will be reported as
|
||||||
|
thin (rule 15/23) whatever the verdict.
|
||||||
|
|
||||||
|
### 3.1 The one engine change this lane makes, and why it is not a thumb on the scale
|
||||||
|
|
||||||
|
`sots-engine` worktree `wip/cr` (rule 21), branched from `main` at `e7e2bd6`.
|
||||||
|
|
||||||
|
* **`research.replace_cascade=on|off`, default `off`.** With it off the binary behaves *exactly* as
|
||||||
|
`main` does today, so P4 measures the shipped behaviour rather than a straw man. With it on, a
|
||||||
|
**replace**-mode call also writes the four `TechNode` words `SetResearched` stamps and the tree's
|
||||||
|
completion-order counter. It does **not** post events, does **not** move the `ObservedTech` vector
|
||||||
|
and does **not** apply a single tech effect — those stay gated on compare mode and stay declared
|
||||||
|
unmodelled. The flag exists so P4 and P5 differ by a **config line and not by a binary**, which is
|
||||||
|
what makes the leaf difference between their autosaves attributable to the cascade.
|
||||||
|
* **A per-call log line in every mode.** The old line was gated on the cascade having run, so a
|
||||||
|
replace run with the cascade off had no counter at all and "a completion happened" could only be
|
||||||
|
inferred from the save — the artefact under test. It now prints `steps`, `completions` (counted
|
||||||
|
from the pass's own step results), `overbudget` and the cascade counters, in compare **and**
|
||||||
|
replace. This is the instrument answering the brief's "show it fired — a count, from the hook
|
||||||
|
itself".
|
||||||
|
|
||||||
|
No new binary facts: `ghidra/addresses.d/cr.json` is **not** created, because this lane reads no new
|
||||||
|
address. Every offset used already exists in the generated header. Host build: 253 targets, **59/59
|
||||||
|
tests pass** (the denominator is the healthy 59, per rule 24's signature check); `clean_room_check`
|
||||||
|
OK; `tools/check_shim_configs.py` OK with 27 registered hooks and all four CR configs
|
||||||
|
(`croff`, `crcompare`, `crreplace0`, `crreplace1`) — the three `hooks=trace` ones marked
|
||||||
|
`# exhaustive` and naming all 27.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Results
|
||||||
|
|
||||||
|
*(added after the runs; nothing above this line is edited)*
|
||||||
572
findings/subsystems/rung-b-rich-turn.md
Normal file
572
findings/subsystems/rung-b-rich-turn.md
Normal file
File diff suppressed because one or more lines are too long
36
ghidra/addresses.d/cz.json
Normal file
36
ghidra/addresses.d/cz.json
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
{
|
||||||
|
"entries": [
|
||||||
|
{
|
||||||
|
"name": "TradeSector_RecomputeStatusMasks",
|
||||||
|
"addr": "0x0088df90",
|
||||||
|
"convention": "thiscall",
|
||||||
|
"prototype": "void TradeSector::RecomputeStatusMasks(TradeSector* this, bool full) -- the writer of all three of the serialised sector masks, and of their `p`-prefixed previous copies. At 0x0088e031-0x0088e058 it copies tssec/tsct/tscr (+0x88/+0x8c/+0x90) into ptssec/ptsct/ptscr (+0x94/+0x98/+0x9c). Then: (1) tssec, written at 0x0088e0af, is the mask over players p of `TradeSector_GetPlayerStatus(this, players[p]) == 0`; (2) tscr, written at 0x0088e733, is the mask over players p of `players[p]->+0x100 != 0` -- the `CnRad` (Commerce Raiding) bool, so tscr is a PLAYER-TECH ROSTER and not a sector property at all; (3) tsct, written at 0x0088e73c, is the mask over players p of `players[p]->+0xff (CnTrd) != 0 AND (tssec >> p) & 1 AND (localMask >> p) & 1`, where localMask is OR'd over the triples FUN_00864670 returns for this sector. Players are StrategyServer+0x50..+0x54 and the bit index is the player's own index field, matching the news-post loop in Slot13RngCalleeB",
|
||||||
|
"status": "verified",
|
||||||
|
"source": "findings/control-flow/raid-intercept-z-word.md (lane CZ 2026-09-09); disassembled from dumps/sots.exe, cross-checked live against az-turn23-tarka-comraid.sav (tscr=127 over seven players all carrying CnRad=True) and against the 24-save AC lineage (tscr=253 over eight players with exactly one CnRad=False)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "TradeSector_GetPlayerStatus",
|
||||||
|
"addr": "0x00819f00",
|
||||||
|
"convention": "thiscall",
|
||||||
|
"prototype": "int TradeSector::GetPlayerStatus(TradeSector* this, ServerPlayer* p) -- returns a status code for one player in one sector; 0 means the player may trade here and is the value TradeSector_RecomputeStatusMasks turns into a tssec bit. 1 = p is null; 5 = p->+0xff (CnTrd) is false; 4 = the sector's member-system vector (this+0x78..+0x7c) is empty, or any member system fails FUN_00743880(sys, p); 2 = no member system counted as friendly; 3 = hostile-owned members outnumber friendly ones; 0 otherwise. Per member system: FUN_007469e0(sys) and sys->+0xc6 skip it; owner = sys->+0x100; FUN_00743fa0(sys) or FUN_0080ecb0(p, owner) counts it friendly, else hostile",
|
||||||
|
"status": "verified",
|
||||||
|
"source": "findings/control-flow/raid-intercept-z-word.md (lane CZ 2026-09-09); disassembled to the next function start from dumps/sots.exe"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "TradeManager_GetNumRoutesSupportedFrom",
|
||||||
|
"addr": "0x008209e0",
|
||||||
|
"convention": "thiscall",
|
||||||
|
"prototype": "int TradeManager::GetNumRoutesSupportedFrom(TradeManager* this, TradeEndpoint* ep, ServerPlayer* owner, bool ignoreInfra) -- the top-of-loop gate in the route rebuilder's per-source helper (called at 0x0086494c, whose caller returns immediately when this is <= 0). Returns 0 unless: owner is non-null; the containing-sector table this->+0x0c indexed by ep->+0x4 (a system index) is non-null; and, for an owner whose Species != 4, the containing sector's tssec (+0x88) has the owner's index bit set. With ep->+0x8 == 0 the source is a SYSTEM and the system's own owner (sys->+0x100) must be this player, and the answer is min(FUN_00819d20(sys), FUN_00819dd0(sys, ignoreInfra ? 1.0f : sys->+0x88)); with ep->+0x8 != 0 the source is a station looked up in StrategyServer+0x80 and the answer is the global at 0x00af0c48",
|
||||||
|
"status": "verified",
|
||||||
|
"source": "findings/control-flow/raid-intercept-z-word.md (lane CZ 2026-09-09); disassembled from dumps/sots.exe"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "TradeManager_BuildRoutesForSource",
|
||||||
|
"addr": "0x008648e0",
|
||||||
|
"convention": "thiscall",
|
||||||
|
"prototype": "void TradeManager::BuildRoutesForSource(TradeManager* this, vector<TradeRoute>* out, TradeEndpoint* from, vector<TradeEndpoint>* candidates) -- called once per source endpoint by ServerTradeManagerImpl_vslot9 (0x00868060). Returns with nothing appended when TradeManager_GetNumRoutesSupportedFrom(from, owner, true) <= 0 at 0x00864956. Otherwise, for each candidate `to`: FUN_0083a690(from, to) must pass and FUN_008194a0(&this->+0x3c, from, to) must find no existing route, and only then is a TradeRoute (vtable 0x00a2d848, 0x38 bytes) constructed and appended",
|
||||||
|
"status": "verified",
|
||||||
|
"source": "findings/control-flow/raid-intercept-z-word.md (lane CZ 2026-09-09); disassembled from dumps/sots.exe"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// GENERATED — do not edit. Facts about Sword of the Stars.exe (GOG 1.8.1).
|
// GENERATED — do not edit. Facts about Sword of the Stars.exe (GOG 1.8.1).
|
||||||
// Source: sots-re ghidra/addresses.json @ 2ad6652, generated 2026-09-09 by tools/gen_addresses.py
|
// Source: sots-re ghidra/addresses.json @ 77b5dd0, generated 2026-09-09 by tools/gen_addresses.py
|
||||||
// Runtime address = (uintptr_t)GetModuleHandle(NULL) + RVA (the exe is ASLR-relocated).
|
// Runtime address = (uintptr_t)GetModuleHandle(NULL) + RVA (the exe is ASLR-relocated).
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
@ -1325,6 +1325,20 @@ constexpr uint32_t ServerSpyManager_DetectionRoll_DrawSite = 0x00487c8a;
|
||||||
constexpr uint32_t SpyCraft_ResetMission = 0x00438070;
|
constexpr uint32_t SpyCraft_ResetMission = 0x00438070;
|
||||||
// data void*[7], the switch jump table SpeciesDef_InitTable 0x005453a0 dispatches through at 0x005453eb (`jmp [eax*4+0x545b60]`) to choose the `Species/%s/...` data-path prefix. READ AS BYTES, the seven entries are 0x005453f2 "Human", 0x005453f9 "Hiver", 0x00545400 "Tarkas", 0x00545407 "Liir", 0x0054541c "_NPC", 0x0054540e "Zuul", 0x00545415 "Morrigi" -- so the species enum is 0 Human, 1 HIVER, 2 TARKAS, 3 LIIR, 4 _NPC, 5 Zuul, 6 MORRIGI. NOTE the case bodies are NOT laid out in case order (index 4 jumps PAST index 5's body), so reading the disassembly top to bottom gives the wrong enum; only the table bytes settle it. SpeciesDef_Get 0x00545cc0 bounds-checks k <= 6, so there are exactly seven. This confirms lane AR's species 0 = Human / species 5 = Zuul from an independent direction and names 1, 2, 3, 4 and 6 for the first time [verified]
|
// data void*[7], the switch jump table SpeciesDef_InitTable 0x005453a0 dispatches through at 0x005453eb (`jmp [eax*4+0x545b60]`) to choose the `Species/%s/...` data-path prefix. READ AS BYTES, the seven entries are 0x005453f2 "Human", 0x005453f9 "Hiver", 0x00545400 "Tarkas", 0x00545407 "Liir", 0x0054541c "_NPC", 0x0054540e "Zuul", 0x00545415 "Morrigi" -- so the species enum is 0 Human, 1 HIVER, 2 TARKAS, 3 LIIR, 4 _NPC, 5 Zuul, 6 MORRIGI. NOTE the case bodies are NOT laid out in case order (index 4 jumps PAST index 5's body), so reading the disassembly top to bottom gives the wrong enum; only the table bytes settle it. SpeciesDef_Get 0x00545cc0 bounds-checks k <= 6, so there are exactly seven. This confirms lane AR's species 0 = Human / species 5 = Zuul from an independent direction and names 1, 2, 3, 4 and 6 for the first time [verified]
|
||||||
constexpr uint32_t SpeciesDef_NameJumpTable = 0x00145b60;
|
constexpr uint32_t SpeciesDef_NameJumpTable = 0x00145b60;
|
||||||
|
// thiscall void __thiscall Game::StrategyAIAgent::ClaimShipsOfFleet(StrategyAIAgent* agent /*ecx*/, StarFleet* fleet /*stack*/) -- EXACTLY ONE CALLER in the whole image, 0x006c1735, the FIRST loop of AssignFleetsAndIssueOrders (0x006c1730-0x006c1740), which walks `param_4` once at function entry before any pass gate. Body: n = ([fleet+0xa8] - [fleet+0xa4]) (the ships vector, StarFleet_off_Ships), and for each StarShip* s in it, push_back(s ? [s+4] : 0) onto the agent's int vector at agent+0x2d8 -- a linear scan of that vector first (0x006a42e0) so an id already present is not added twice, then the MSVC push_back grow path (capacity check against 0x3ffffffe, 0x00483410 to reallocate). `[s+4]` is StarShip's id, the same word StarFleet_off_Id names on a fleet. BECAUSE IT HAS ONE CALLER AND IS CALLED ONCE PER ELEMENT AT THE HEAD OF THE WALK, a detour on it records the acquired-fleet vector in visit order with no return-address filter and no mid-function patch: it is the whole instrument of lane BU's stage-2 probe [verified]
|
||||||
|
constexpr uint32_t StrategyAIAgent_ClaimShipsOfFleet = 0x002a4290;
|
||||||
|
// thiscall void __thiscall Game::StrategyAIAgent::ReleaseShipsOfFleet(StrategyAIAgent* agent /*ecx*/, StarFleet* fleet /*stack*/) -- RET 4. EXACTLY ONE CALLER, 0x006c1765, the second loop of AssignFleetsAndIssueOrders (0x006c1760-0x006c1770), which is entered at 0x006c1753 AFTER the element loop has walked the vector to exhaustion (`jmp 0x6c1753` at 0x006c21c4). The exact inverse of ClaimShipsOfFleet: for each StarShip* s in the fleet's ships vector it finds [s+4] in the agent's int vector at agent+0x2d8, memmoves the tail down (import 0x009dd30c) and does `[agent+0x2dc] -= 4`. Same one-call-per-element shape over the SAME vector in the SAME order, so it is a free second witness of the visit order taken after the loop rather than before it [verified]
|
||||||
|
constexpr uint32_t StrategyAIAgent_ReleaseShipsOfFleet = 0x0029da10;
|
||||||
|
// offset std::vector<int> claimed ship ids (_Myfirst @+0x2d8, _Mylast @+0x2dc, _Myend @+0x2e0). Read and written ONLY by the claim/release pair above, both of which are exclusive to AssignFleetsAndIssueOrders: the fleets acquired for a task have their ships' ids parked here for the duration of the assignment walk and removed when it is done. Enumerated from the push_back grow path at 0x006a4338-0x006a4356 (which reads +0x2e0 as _Myend via `mov ecx,[esi+8]` with esi = agent+0x2d8) and the erase path at 0x0069da63-0x0069da81 [verified]
|
||||||
|
constexpr uint32_t StrategyAIAgent_off_ClaimedShipIds = 0x000002d8;
|
||||||
|
// thiscall void TradeSector::RecomputeStatusMasks(TradeSector* this, bool full) -- the writer of all three of the serialised sector masks, and of their `p`-prefixed previous copies. At 0x0088e031-0x0088e058 it copies tssec/tsct/tscr (+0x88/+0x8c/+0x90) into ptssec/ptsct/ptscr (+0x94/+0x98/+0x9c). Then: (1) tssec, written at 0x0088e0af, is the mask over players p of `TradeSector_GetPlayerStatus(this, players[p]) == 0`; (2) tscr, written at 0x0088e733, is the mask over players p of `players[p]->+0x100 != 0` -- the `CnRad` (Commerce Raiding) bool, so tscr is a PLAYER-TECH ROSTER and not a sector property at all; (3) tsct, written at 0x0088e73c, is the mask over players p of `players[p]->+0xff (CnTrd) != 0 AND (tssec >> p) & 1 AND (localMask >> p) & 1`, where localMask is OR'd over the triples FUN_00864670 returns for this sector. Players are StrategyServer+0x50..+0x54 and the bit index is the player's own index field, matching the news-post loop in Slot13RngCalleeB [verified]
|
||||||
|
constexpr uint32_t TradeSector_RecomputeStatusMasks = 0x0048df90;
|
||||||
|
// thiscall int TradeSector::GetPlayerStatus(TradeSector* this, ServerPlayer* p) -- returns a status code for one player in one sector; 0 means the player may trade here and is the value TradeSector_RecomputeStatusMasks turns into a tssec bit. 1 = p is null; 5 = p->+0xff (CnTrd) is false; 4 = the sector's member-system vector (this+0x78..+0x7c) is empty, or any member system fails FUN_00743880(sys, p); 2 = no member system counted as friendly; 3 = hostile-owned members outnumber friendly ones; 0 otherwise. Per member system: FUN_007469e0(sys) and sys->+0xc6 skip it; owner = sys->+0x100; FUN_00743fa0(sys) or FUN_0080ecb0(p, owner) counts it friendly, else hostile [verified]
|
||||||
|
constexpr uint32_t TradeSector_GetPlayerStatus = 0x00419f00;
|
||||||
|
// thiscall int TradeManager::GetNumRoutesSupportedFrom(TradeManager* this, TradeEndpoint* ep, ServerPlayer* owner, bool ignoreInfra) -- the top-of-loop gate in the route rebuilder's per-source helper (called at 0x0086494c, whose caller returns immediately when this is <= 0). Returns 0 unless: owner is non-null; the containing-sector table this->+0x0c indexed by ep->+0x4 (a system index) is non-null; and, for an owner whose Species != 4, the containing sector's tssec (+0x88) has the owner's index bit set. With ep->+0x8 == 0 the source is a SYSTEM and the system's own owner (sys->+0x100) must be this player, and the answer is min(FUN_00819d20(sys), FUN_00819dd0(sys, ignoreInfra ? 1.0f : sys->+0x88)); with ep->+0x8 != 0 the source is a station looked up in StrategyServer+0x80 and the answer is the global at 0x00af0c48 [verified]
|
||||||
|
constexpr uint32_t TradeManager_GetNumRoutesSupportedFrom = 0x004209e0;
|
||||||
|
// thiscall void TradeManager::BuildRoutesForSource(TradeManager* this, vector<TradeRoute>* out, TradeEndpoint* from, vector<TradeEndpoint>* candidates) -- called once per source endpoint by ServerTradeManagerImpl_vslot9 (0x00868060). Returns with nothing appended when TradeManager_GetNumRoutesSupportedFrom(from, owner, true) <= 0 at 0x00864956. Otherwise, for each candidate `to`: FUN_0083a690(from, to) must pass and FUN_008194a0(&this->+0x3c, from, to) must find no existing route, and only then is a TradeRoute (vtable 0x00a2d848, 0x38 bytes) constructed and appended [verified]
|
||||||
|
constexpr uint32_t TradeManager_BuildRoutesForSource = 0x004648e0;
|
||||||
// thiscall void (Game::StrategyAIAgent::Streamable* this, Mars::Stream* s) // the body of every `Player.<id>.AIAgent` CD block. 36 wire items, NO conditionals: the only `if` the decompiler shows around `lnat` is an inlined std::vector destructor whose operator delete is marked noreturn, and both paths converge at 0x006c72e8. The agent object is *(this+4) [verified]
|
// thiscall void (Game::StrategyAIAgent::Streamable* this, Mars::Stream* s) // the body of every `Player.<id>.AIAgent` CD block. 36 wire items, NO conditionals: the only `if` the decompiler shows around `lnat` is an inlined std::vector destructor whose operator delete is marked noreturn, and both paths converge at 0x006c72e8. The agent object is *(this+4) [verified]
|
||||||
constexpr uint32_t Game_StrategyAIAgent_Streamable_Write = 0x002c6f00;
|
constexpr uint32_t Game_StrategyAIAgent_Streamable_Write = 0x002c6f00;
|
||||||
// thiscall bool (Game::StrategyAIAgent::Streamable* this, Mars::Stream* s) [verified]
|
// thiscall bool (Game::StrategyAIAgent::Streamable* this, Mars::Stream* s) [verified]
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,13 @@ BLK_RE = re.compile(
|
||||||
r"f3=(\d):(\S+),(\S+),(\S+) civ=(\d)")
|
r"f3=(\d):(\S+),(\S+),(\S+) civ=(\d)")
|
||||||
LISTS_RE = re.compile(r"^ailists seq=(\d+) blk=(\d+) pid=(-?\d+) nonEmpty=\d+ sizes\(1\.\.27\)=\[([^\]]*)\]")
|
LISTS_RE = re.compile(r"^ailists seq=(\d+) blk=(\d+) pid=(-?\d+) nonEmpty=\d+ sizes\(1\.\.27\)=\[([^\]]*)\]")
|
||||||
ELEM_RE = re.compile(r"^aielem blk=(\d+) pid=(-?\d+) list=(\d+) idx=(\d+) .*? hex=\[([^\]]*)\]")
|
ELEM_RE = re.compile(r"^aielem blk=(\d+) pid=(-?\d+) list=(\d+) idx=(\d+) .*? hex=\[([^\]]*)\]")
|
||||||
|
# The two records a DEEP dump adds (`aiorders.deep=on`). Each says which WORD of the fixed
|
||||||
|
# element window it followed, so it lands on exactly the field the map already calls a `v` or a
|
||||||
|
# string -- it is not a second, parallel field map.
|
||||||
|
VEC_RE = re.compile(r"^aivec blk=(\d+) pid=(-?\d+) list=(\d+) idx=(\d+) at=w(\d+) "
|
||||||
|
r"first=\S+ cap=(\d+) count=(\d+) ints=\[([^\]]*)\]")
|
||||||
|
STR_RE = re.compile(r"^aistr blk=(\d+) pid=(-?\d+) list=(\d+) idx=(\d+) at=w(\d+) "
|
||||||
|
r"sso=\d+ len=(\d+) text=\"(.*)\"\s*$")
|
||||||
|
|
||||||
|
|
||||||
def f32(word):
|
def f32(word):
|
||||||
|
|
@ -112,6 +119,8 @@ def parse_log(path):
|
||||||
"civ": m.group(19) == "1",
|
"civ": m.group(19) == "1",
|
||||||
"sizes": [0] * 27,
|
"sizes": [0] * 27,
|
||||||
"elems": {},
|
"elems": {},
|
||||||
|
"vecs": {},
|
||||||
|
"strs": {},
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
m = LISTS_RE.match(line)
|
m = LISTS_RE.match(line)
|
||||||
|
|
@ -131,11 +140,41 @@ def parse_log(path):
|
||||||
blk = batch(seq)["blocks"].get(idx)
|
blk = batch(seq)["blocks"].get(idx)
|
||||||
if blk is not None:
|
if blk is not None:
|
||||||
blk["elems"].setdefault(listno, {})[elemidx] = words
|
blk["elems"].setdefault(listno, {})[elemidx] = words
|
||||||
|
continue
|
||||||
|
m = VEC_RE.match(line)
|
||||||
|
if m:
|
||||||
|
seq = max(batches) if batches else 0
|
||||||
|
idx, listno, elemidx = int(m.group(1)), int(m.group(3)), int(m.group(4))
|
||||||
|
at, count = int(m.group(5)), int(m.group(7))
|
||||||
|
ints = [int(x) for x in m.group(8).split()]
|
||||||
|
blk = batch(seq)["blocks"].get(idx)
|
||||||
|
if blk is not None:
|
||||||
|
# `count` is what the dump says it followed; `ints` is what it printed. A
|
||||||
|
# disagreement is a defect in the record and this tool refuses to guess which
|
||||||
|
# half is right -- the element keeps its shallow (length-only) form.
|
||||||
|
if len(ints) == count:
|
||||||
|
blk["vecs"].setdefault(listno, {}).setdefault(elemidx, {})[at] = ints
|
||||||
|
continue
|
||||||
|
m = STR_RE.match(line)
|
||||||
|
if m:
|
||||||
|
seq = max(batches) if batches else 0
|
||||||
|
idx, listno, elemidx = int(m.group(1)), int(m.group(3)), int(m.group(4))
|
||||||
|
at, text = int(m.group(5)), m.group(7)
|
||||||
|
blk = batch(seq)["blocks"].get(idx)
|
||||||
|
if blk is not None:
|
||||||
|
blk["strs"].setdefault(listno, {}).setdefault(elemidx, {})[at] = text
|
||||||
return batches
|
return batches
|
||||||
|
|
||||||
|
|
||||||
def element_fields(listno, words):
|
def element_fields(listno, words, deep=None, problems=None):
|
||||||
"""The wire fields of one element, as `.tcb` tokens."""
|
"""The wire fields of one element, as `.tcb` tokens.
|
||||||
|
|
||||||
|
`deep` is {word index -> [values]} from a deep dump's `aivec` rows. It is consulted ONLY at
|
||||||
|
a word the shallow map already types as a vector: the deep rows say which word they followed,
|
||||||
|
so a row that lands anywhere else is a disagreement between the two records and is reported,
|
||||||
|
never silently used to invent a field the map does not have.
|
||||||
|
"""
|
||||||
|
deep = deep or {}
|
||||||
spec = LIST_MAP.get(listno)
|
spec = LIST_MAP.get(listno)
|
||||||
if spec is None:
|
if spec is None:
|
||||||
# An unmapped list: record that the element exists and nothing about it. The command
|
# An unmapped list: record that the element exists and nothing about it. The command
|
||||||
|
|
@ -156,14 +195,29 @@ def element_fields(listno, words):
|
||||||
elif kind == "v":
|
elif kind == "v":
|
||||||
if k + 1 >= len(words):
|
if k + 1 >= len(words):
|
||||||
out.append("?")
|
out.append("?")
|
||||||
|
continue
|
||||||
|
n = (words[k + 1] - w) // 4
|
||||||
|
values = deep.get(k)
|
||||||
|
if values is None:
|
||||||
|
out.append("v%d" % n)
|
||||||
|
elif len(values) != n:
|
||||||
|
# The begin/end pair and the followed contents disagree. Keep the length-only
|
||||||
|
# form: a route whose hops we are not sure of must stay unapplied.
|
||||||
|
if problems is not None:
|
||||||
|
problems.append("list %d elem %d word %d: begin/end says %d hop(s), the deep "
|
||||||
|
"row printed %d -- kept as length-only"
|
||||||
|
% (listno, k, k, n, len(values)))
|
||||||
|
out.append("v%d" % n)
|
||||||
else:
|
else:
|
||||||
out.append("v%d" % ((words[k + 1] - w) // 4))
|
out.append("v%d:%s" % (n, ",".join(str(v) for v in values)))
|
||||||
else:
|
else:
|
||||||
out.append("?")
|
out.append("?")
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
def emit(batch, seq, source, names, seeds, input_name):
|
def emit(batch, seq, source, names, seeds, input_name, problems=None):
|
||||||
|
if problems is None:
|
||||||
|
problems = []
|
||||||
lines = ["tcb 1",
|
lines = ["tcb 1",
|
||||||
"meta source %s" % source,
|
"meta source %s" % source,
|
||||||
"meta input %s" % input_name,
|
"meta input %s" % input_name,
|
||||||
|
|
@ -194,10 +248,35 @@ def emit(batch, seq, source, names, seeds, input_name):
|
||||||
continue
|
continue
|
||||||
lines.append("list %d %d %d" % (idx, listno, n))
|
lines.append("list %d %d %d" % (idx, listno, n))
|
||||||
have = b["elems"].get(listno, {})
|
have = b["elems"].get(listno, {})
|
||||||
|
vecs = b.get("vecs", {}).get(listno, {})
|
||||||
|
strs = b.get("strs", {}).get(listno, {})
|
||||||
|
spec = LIST_MAP.get(listno) or []
|
||||||
|
vecwords = {k for kind, k in spec if kind == "v"}
|
||||||
for e in range(n):
|
for e in range(n):
|
||||||
words = have.get(e)
|
words = have.get(e)
|
||||||
fields = element_fields(listno, words) if words is not None else ["?"]
|
deep = vecs.get(e, {})
|
||||||
|
fields = (element_fields(listno, words, deep, problems)
|
||||||
|
if words is not None else ["?"])
|
||||||
lines.append("elem %d %d %d %s" % (idx, listno, e, " ".join(fields)))
|
lines.append("elem %d %d %d %s" % (idx, listno, e, " ".join(fields)))
|
||||||
|
# A deep row the field map has no vector at. It is a real observation and it is
|
||||||
|
# NOT a field: recording it as one would be inventing a mapping the dump does not
|
||||||
|
# justify. It goes in as a comment so the record keeps it and the parser does
|
||||||
|
# not read it, and it is counted as a followed payload this tool cannot place.
|
||||||
|
for at in sorted(deep):
|
||||||
|
if at in vecwords:
|
||||||
|
continue
|
||||||
|
problems.append(
|
||||||
|
"list %d elem %d: a followed vector at word %d, which the field map does "
|
||||||
|
"not type as a vector -- recorded as a comment, not applied" % (listno, e, at))
|
||||||
|
lines.append("# observed list %d elem %d word %d vector: [%s]"
|
||||||
|
% (listno, e, at, ",".join(str(v) for v in deep[at])))
|
||||||
|
for at in sorted(strs.get(e, {})):
|
||||||
|
problems.append(
|
||||||
|
"list %d elem %d: a followed string at word %d, which the field map types "
|
||||||
|
"as part of an object it cannot read -- recorded as a comment, not applied"
|
||||||
|
% (listno, e, at))
|
||||||
|
lines.append("# observed list %d elem %d word %d string: %s"
|
||||||
|
% (listno, e, at, strs[e][at]))
|
||||||
return "\n".join(lines) + "\n"
|
return "\n".join(lines) + "\n"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -241,7 +320,10 @@ def main(argv=None):
|
||||||
return 2
|
return 2
|
||||||
seeds.append((netid, value))
|
seeds.append((netid, value))
|
||||||
|
|
||||||
text = emit(batches[seq], seq, a.log.split("/")[-1], names, seeds, a.input)
|
problems = []
|
||||||
|
text = emit(batches[seq], seq, a.log.split("/")[-1], names, seeds, a.input, problems)
|
||||||
|
for p in problems:
|
||||||
|
print("deep: %s" % p, file=sys.stderr)
|
||||||
if a.out:
|
if a.out:
|
||||||
with open(a.out, "w") as f:
|
with open(a.out, "w") as f:
|
||||||
f.write(text)
|
f.write(text)
|
||||||
|
|
|
||||||
63
tools/gate.sh
Executable file
63
tools/gate.sh
Executable file
|
|
@ -0,0 +1,63 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# The engine gate, as a script instead of as the integrator's memory.
|
||||||
|
#
|
||||||
|
# Why this exists: for a whole day the gate reported 59/59 while the two tests that read
|
||||||
|
# the save corpus were SKIPPING, because SOTS_SAVES_DIR was never set on CT111. The corpus
|
||||||
|
# had grown from 22 to 43 saves and the coverage ratchet had broken exactly as rule 27 says
|
||||||
|
# it should -- and a writer defect had appeared on 12 of them -- and the gate could not see
|
||||||
|
# either. A green verdict on a harness that is comparing nothing (rule 1), delivered by the
|
||||||
|
# person whose job was to notice it.
|
||||||
|
#
|
||||||
|
# Each check is its own command and its own exit code. Nothing here is &&-chained across
|
||||||
|
# checks, because a chain that short-circuits reports a check that never ran (rule 22's
|
||||||
|
# cousin, paid for once already).
|
||||||
|
#
|
||||||
|
# Usage: tools/gate.sh [--fresh] --fresh: rm -rf the remote build dirs first (rule 24)
|
||||||
|
set -u
|
||||||
|
|
||||||
|
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
|
||||||
|
FRESH=0
|
||||||
|
[ "${1:-}" = "--fresh" ] && FRESH=1
|
||||||
|
|
||||||
|
ct() { ssh spicy "pct exec $CT -- bash -lc '$*'"; }
|
||||||
|
|
||||||
|
status=0
|
||||||
|
report() { # name rc
|
||||||
|
if [ "$2" -eq 0 ]; then echo "GATE ok $1"; else echo "GATE FAIL $1 (exit $2)"; status=1; fi
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "== gate: $ENGINE @ $(git -C "$ENGINE" rev-parse --short HEAD), corpus $(ls "$RE"/verify/results/saves/*.sav | wc -l) saves, fresh=$FRESH"
|
||||||
|
|
||||||
|
# 1. clean-room, host
|
||||||
|
( cd "$ENGINE" && bash tools/clean_room_check.sh ); report clean-room $?
|
||||||
|
|
||||||
|
# 2. shim config structure, host
|
||||||
|
( cd "$ENGINE" && uv run --quiet python3 tools/check_shim_configs.py ); report shim-configs $?
|
||||||
|
|
||||||
|
# 3. sync the tree -- BOTH halves of rule 24: exclude local build dirs, and clear the remote ones
|
||||||
|
rsync -a --delete --exclude '.git' --exclude 'build*' -e ssh "$ENGINE"/ spicy:/tmp/eng-gate/; report sync-to-host $?
|
||||||
|
if [ $FRESH -eq 1 ]; then ct "rm -rf $REMOTE_TREE/build-host $REMOTE_TREE/build-shim"; report clear-remote-builds $?; fi
|
||||||
|
ssh spicy "tar -C /tmp/eng-gate -cf - . | pct exec $CT -- tar -C $REMOTE_TREE -xf -"; report sync-to-ct $?
|
||||||
|
|
||||||
|
# 4. sync the corpus -- the tests are only a gate if they run against it
|
||||||
|
rsync -a --delete --include='*.sav' --exclude='*' -e ssh "$RE"/verify/results/saves/ spicy:/tmp/sots-corpus/; report corpus-to-host $?
|
||||||
|
ssh spicy "pct exec $CT -- mkdir -p $REMOTE_CORPUS && tar -C /tmp/sots-corpus -cf - . | pct exec $CT -- tar -C $REMOTE_CORPUS -xf -"; report corpus-to-ct $?
|
||||||
|
NCORPUS=$(ct "ls $REMOTE_CORPUS | grep -c .sav")
|
||||||
|
echo "GATE info corpus on CT111: $NCORPUS saves"
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# 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
|
||||||
1170
verify/results/standalone/cv/cv-input-vs-bp-pinB.txt
Normal file
1170
verify/results/standalone/cv/cv-input-vs-bp-pinB.txt
Normal file
File diff suppressed because it is too large
Load diff
160
verify/results/standalone/cv/cv-leaf-worklist.txt
Normal file
160
verify/results/standalone/cv/cv-leaf-worklist.txt
Normal file
|
|
@ -0,0 +1,160 @@
|
||||||
|
total leaves compared-and-differing: 1092
|
||||||
|
|
||||||
|
539 morale event ring (per-system cme2)
|
||||||
|
130 /Sim/systems/Sys[]/cme2/.[]/mid
|
||||||
|
111 /Sim/systems/Sys[]/cme2/.[]/mtr
|
||||||
|
80 /Sim/systems/Sys[]/cme2/.[]/mdsc
|
||||||
|
79 /Sim/systems/Sys[]/cme2/.[]/mtp
|
||||||
|
72 /Sim/systems/Sys[]/cme2/.[]/mn
|
||||||
|
67 /Sim/systems/Sys[]/cme2/.[]/mfx/mv
|
||||||
|
|
||||||
|
154 colony growth + repair + bonuses (per system)
|
||||||
|
18 /Sim/systems/Sys[]/PvInfra
|
||||||
|
17 /Sim/systems/Sys[]/RepCur
|
||||||
|
17 /Sim/systems/Sys[]/RepMax
|
||||||
|
16 /Sim/systems/Sys[]/PvPop
|
||||||
|
10 /Sim/systems/Sys[]/pbon
|
||||||
|
10 /Sim/systems/Sys[]/ibon
|
||||||
|
6 /Sim/systems/Sys[]/Pop
|
||||||
|
6 /Sim/systems/Sys[]/Infra
|
||||||
|
5 /Sim/systems/Sys[]/Suit
|
||||||
|
5 /Sim/systems/Sys[]/PvSuit
|
||||||
|
5 /Sim/systems/Sys[]/ntdev
|
||||||
|
4 /Sim/systems/Sys[]/PvCM/mv
|
||||||
|
4 /Sim/systems/Sys[]/PvRes
|
||||||
|
4 /Sim/systems/Sys[]/Rts/SRt
|
||||||
|
4 /Sim/systems/Sys[]/Rts/SRsc
|
||||||
|
4 /Sim/systems/Sys[]/Pop2/PopG/PopC
|
||||||
|
3 /Sim/systems/Sys[]/cm/mv
|
||||||
|
3 /Sim/systems/Sys[]/PvPop2/PopG/PopC
|
||||||
|
3 /Sim/systems/Sys[]/haltv[]
|
||||||
|
1 /Sim/systems/Sys[]/Pop2/PopG
|
||||||
|
1 /Sim/systems/Sys[]/Pop2/PopNG
|
||||||
|
1 /Sim/systems/Sys[]/Rts/SRtf
|
||||||
|
1 /Sim/systems/Sys[]/Rts/SRi
|
||||||
|
1 /Sim/systems/Sys[]/dcs/PopG
|
||||||
|
1 /Sim/systems/Sys[]/dcs/PopNG
|
||||||
|
1 /Sim/systems/Sys[]/Rts/SRoh
|
||||||
|
1 /Sim/systems/Sys[]/TnsOH
|
||||||
|
1 /Sim/systems/Sys[]/PvCM/msp
|
||||||
|
1 /Sim/systems/Sys[]/PvCM/mnsp
|
||||||
|
|
||||||
|
150 fleet objects: position, route, range, layout
|
||||||
|
29 /Sim/fleets/Flt[]/ships/Ship[]/Range
|
||||||
|
24 /Sim/fleets/Flt[]/Pos/.[]
|
||||||
|
24 /Sim/fleets/Flt[]/PrvPos/.[]
|
||||||
|
11 /Sim/fleets/Flt[]
|
||||||
|
11 /Sim/fleets/Flt[]/Lay/.[]
|
||||||
|
11 /Sim/fleets/Flt[]/ships/Ship[]
|
||||||
|
7 /Sim/fleets/Flt[]/FtFlg
|
||||||
|
4 /Sim/fleets/Flt[]/Ftpae
|
||||||
|
4 /Sim/fleets/Flt[]/FPlan
|
||||||
|
4 /Sim/fleets/Flt[]/LocID
|
||||||
|
4 /Sim/fleets/Flt[]/HFPlan
|
||||||
|
4 /Sim/fleets/Flt[]/NShips
|
||||||
|
4 /Sim/fleets/Flt[]/FPlan/FPeta2
|
||||||
|
3 /Sim/fleets/Flt[]/ships/Ship[]/Health/.[]
|
||||||
|
3 /Sim/fleets/Flt[]/FtOrig/.[]
|
||||||
|
2 /Sim/fleets/Flt[]/ships/Ship[]/RefCap
|
||||||
|
1 /Sim/fleets/Flt[]/ships/Ship[]/Act
|
||||||
|
|
||||||
|
79 observed designs / techs / weapons (per player)
|
||||||
|
21 /Sim/players/Player[]/odes/.[]/otnL
|
||||||
|
17 /Sim/players/Player[]/odes/.[]/otnF
|
||||||
|
17 /Sim/players/Player[]/odes/.[]/odid
|
||||||
|
17 /Sim/players/Player[]/otch/.[]/otnL
|
||||||
|
5 /Sim/players/Player[]/owep/.[]/otnL
|
||||||
|
2 /Sim/players/Player[]/otch/.[]
|
||||||
|
|
||||||
|
30 other player leaves
|
||||||
|
4 /Sim/players/Player[]/Events/Events/.[]
|
||||||
|
3 /Sim/players/Player[]/designs/Des[]
|
||||||
|
2 /Sim/players/Player[]/Sav
|
||||||
|
2 /Sim/players/Player[]/Events/EvNxID
|
||||||
|
2 /Sim/players/Player[]/BnkPr
|
||||||
|
2 /Sim/players/Player[]/BnkEl
|
||||||
|
2 /Sim/players/Player[]/nmeid
|
||||||
|
1 /Sim/players/Player[]/OwnId[]
|
||||||
|
1 /Sim/players/Player[]/TechTree/St[]
|
||||||
|
1 /Sim/players/Player[]/TechTree/TResDone[]
|
||||||
|
1 /Sim/players/Player[]/TechTree/TAcq[]
|
||||||
|
1 /Sim/players/Player[]/TechTree/TiAcq[]
|
||||||
|
1 /Sim/players/Player[]/TerraMod
|
||||||
|
1 /Sim/players/Player[]/Maint
|
||||||
|
1 /Sim/players/Player[]/FNG/FNGNum
|
||||||
|
1 /Sim/players/Player[]/PvSav
|
||||||
|
1 /Sim/players/Player[]/lboid
|
||||||
|
1 /Sim/players/Player[]/ResTNm
|
||||||
|
1 /Sim/players/Player[]/NumOwn
|
||||||
|
1 /Sim/players/Player[]/NumDes
|
||||||
|
|
||||||
|
23 visibility remainder (TShn)
|
||||||
|
15 /Sim/systems/Sys[]/TShn[]
|
||||||
|
8 /Sim/systems/Sys[]/TShn
|
||||||
|
|
||||||
|
23 system<->fleet membership
|
||||||
|
12 /Sim/systems/Sys[]/Flt[]
|
||||||
|
7 /Sim/systems/Sys[]/NumFlts
|
||||||
|
4 /Sim/systems/Sys[]/Flt
|
||||||
|
|
||||||
|
20 ship census records (ShipRecs)
|
||||||
|
7 /Sim/players/Player[]/ShipRecs/sri[]
|
||||||
|
6 /Sim/players/Player[]/ShipRecs/srb[]
|
||||||
|
2 /Sim/players/Player[]/ShipRecs/srd[]
|
||||||
|
2 /Sim/players/Player[]/ShipRecs/src[]
|
||||||
|
2 /Sim/players/Player[]/ShipRecs/srl[]
|
||||||
|
1 /Sim/players/Player[]/ShipRecs/srbd
|
||||||
|
|
||||||
|
20 build queues (ship construction)
|
||||||
|
10 /Sim/systems/Sys[]/BQ/ords/.[]
|
||||||
|
4 /Sim/systems/Sys[]/BQ/ords/.
|
||||||
|
3 /Sim/systems/Sys[]/BQ/ords/.[]/ordID
|
||||||
|
1 /Sim/systems/Sys[]/BQ
|
||||||
|
1 /Sim/systems/Sys[]/BQ/ords
|
||||||
|
1 /Sim/systems/Sys[]/BQ/ords/.[]/conleft
|
||||||
|
|
||||||
|
15 other system leaves
|
||||||
|
7 /Sim/systems/Sys[]/Bats2
|
||||||
|
3 /Sim/systems/Sys[]/DefF
|
||||||
|
1 /Sim/systems/Sys[]/RfRFlags
|
||||||
|
1 /Sim/systems/Sys[]/TAcq
|
||||||
|
1 /Sim/systems/Sys[]/PID[]
|
||||||
|
1 /Sim/systems/Sys[]/OID[]
|
||||||
|
1 /Sim/systems/Sys[]/FFlags
|
||||||
|
|
||||||
|
13 combat reports (crep) and CD
|
||||||
|
6 /Sim/crep[]/prep/.[]/nshp[]
|
||||||
|
2 /CD[]/CmbR[]
|
||||||
|
2 /CD[]/apr/.[]
|
||||||
|
1 /CD[]/NCmbR
|
||||||
|
1 /CD[]/NPrvVa
|
||||||
|
1 /CD[]/apr/.
|
||||||
|
|
||||||
|
10 master id lists + counters + generator
|
||||||
|
1 /Sim/Act
|
||||||
|
1 /Sim/NMnx
|
||||||
|
1 /Sim/DesignIDs[]
|
||||||
|
1 /Sim/FleetIDs[]
|
||||||
|
1 /Sim/ShipIDs[]
|
||||||
|
1 /Sim/ModCount
|
||||||
|
1 /Sim/RNG/.
|
||||||
|
1 /Sim/cmbtid
|
||||||
|
1 /Sim/NumFlts
|
||||||
|
1 /Sim/NumActs
|
||||||
|
|
||||||
|
8 turn record archive (turnstats)
|
||||||
|
8 /Sim/turnstats/history/hist[]/stats[]
|
||||||
|
|
||||||
|
6 trade manager
|
||||||
|
2 /Sim/trdmgr/trades/Trade[]/fwarn/.[]
|
||||||
|
2 /Sim/trdmgr/trades/Trade[]/tsflt[]
|
||||||
|
1 /Sim/trdmgr/trades/Trade[]/fwarn/.
|
||||||
|
1 /Sim/trdmgr/trades/Trade[]/fwarn/.[]/ntrns
|
||||||
|
|
||||||
|
1 save-writer defect (sprjs/usp)
|
||||||
|
1 /Sim/sprjs/usp
|
||||||
|
|
||||||
|
1 derived checksum
|
||||||
|
1 /Summary/Checksum
|
||||||
|
|
||||||
|
UNGROUPED (0):
|
||||||
1096
verify/results/standalone/cv/cv-noreplay-vs-bp-pinB.txt
Normal file
1096
verify/results/standalone/cv/cv-noreplay-vs-bp-pinB.txt
Normal file
File diff suppressed because it is too large
Load diff
206
verify/results/standalone/cv/cv-replay-run.log
Normal file
206
verify/results/standalone/cv/cv-replay-run.log
Normal file
|
|
@ -0,0 +1,206 @@
|
||||||
|
load: /home/alex/sots-re/verify/results/saves/ad-turn27-two-raiders.sav
|
||||||
|
1052300 inflated bytes, 0 error(s), 1 warning(s)
|
||||||
|
turn 27, frame 27, modCount 1428, 8 player(s), 28 system(s), 54 fleet(s)
|
||||||
|
data: ./sotsdata -- 885 section(s) over 7 race(s), 5196 string(s), 46 load problem(s)
|
||||||
|
turn-commands: br2-deep.tcb -- 8 block(s), 3 seed(s)
|
||||||
|
source: BR2-deep-aiorders.txt
|
||||||
|
input: ad-turn27-two-raiders.sav
|
||||||
|
batch: seq=2 n=8
|
||||||
|
note: the load-time batch is excluded; this is the End-Turn submission
|
||||||
|
|
||||||
|
turn commands: 8 block(s), 4 submitting, 85 command(s)
|
||||||
|
ModCount bumps charged 70
|
||||||
|
applied 4 transcribed 0 declined 36 incomplete 45
|
||||||
|
leaves written by commands 0
|
||||||
|
|
||||||
|
step blk player cost disposition command
|
||||||
|
6 1 32 1 incomplete list 5 system rates [0]
|
||||||
|
the capture does not carry all eight fields of the rates frame
|
||||||
|
6 1 32 1 incomplete list 5 system rates [1]
|
||||||
|
the capture does not carry all eight fields of the rates frame
|
||||||
|
6 1 32 1 incomplete list 5 system rates [2]
|
||||||
|
the capture does not carry all eight fields of the rates frame
|
||||||
|
6 1 32 1 incomplete list 5 system rates [3]
|
||||||
|
the capture does not carry all eight fields of the rates frame
|
||||||
|
6 1 32 1 incomplete list 5 system rates [4]
|
||||||
|
the capture does not carry all eight fields of the rates frame
|
||||||
|
6 1 32 1 incomplete list 5 system rates [5]
|
||||||
|
the capture does not carry all eight fields of the rates frame
|
||||||
|
6 1 32 1 incomplete list 5 system rates [6]
|
||||||
|
the capture does not carry all eight fields of the rates frame
|
||||||
|
6 1 32 1 incomplete list 5 system rates [7]
|
||||||
|
the capture does not carry all eight fields of the rates frame
|
||||||
|
6 1 32 1 incomplete list 5 system rates [8]
|
||||||
|
the capture does not carry all eight fields of the rates frame
|
||||||
|
6 1 32 1 incomplete list 5 system rates [9]
|
||||||
|
the capture does not carry all eight fields of the rates frame
|
||||||
|
6 1 32 1 incomplete list 5 system rates [10]
|
||||||
|
the capture does not carry all eight fields of the rates frame
|
||||||
|
6 1 32 1 incomplete list 5 system rates [11]
|
||||||
|
the capture does not carry all eight fields of the rates frame
|
||||||
|
6 1 32 1 incomplete list 5 system rates [12]
|
||||||
|
the capture does not carry all eight fields of the rates frame
|
||||||
|
6 1 32 1 incomplete list 5 system rates [13]
|
||||||
|
the capture does not carry all eight fields of the rates frame
|
||||||
|
6 1 32 1 incomplete list 5 system rates [14]
|
||||||
|
the capture does not carry all eight fields of the rates frame
|
||||||
|
7 1 32 0 incomplete list 23 population [0]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
7 1 32 0 incomplete list 23 population [1]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
7 1 32 0 incomplete list 23 population [2]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
7 1 32 0 incomplete list 23 population [3]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
7 1 32 0 incomplete list 23 population [4]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
7 1 32 0 incomplete list 23 population [5]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
7 1 32 0 incomplete list 23 population [6]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
7 1 32 0 incomplete list 23 population [7]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
7 1 32 0 incomplete list 23 population [8]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
7 1 32 0 incomplete list 23 population [9]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
7 1 32 0 incomplete list 23 population [10]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
7 1 32 0 incomplete list 23 population [11]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
7 1 32 0 incomplete list 23 population [12]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
7 1 32 0 incomplete list 23 population [13]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
7 1 32 0 incomplete list 23 population [14]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
9 0 16 1 applied gate loop A (group5, research target, research rate) / research rate
|
||||||
|
the empire research/savings slider; the applier is a small handler and only this field write is modelled from it
|
||||||
|
9 1 32 1 applied gate loop A (group5, research target, research rate) / research rate
|
||||||
|
the empire research/savings slider; the applier is a small handler and only this field write is modelled from it
|
||||||
|
9 2 496 1 applied gate loop A (group5, research target, research rate) / research rate
|
||||||
|
the empire research/savings slider; the applier is a small handler and only this field write is modelled from it
|
||||||
|
9 3 512 1 applied gate loop A (group5, research target, research rate) / research rate
|
||||||
|
the empire research/savings slider; the applier is a small handler and only this field write is modelled from it
|
||||||
|
10 1 32 1 incomplete list 1 new designs [0]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
10 1 32 1 incomplete list 1 new designs [1]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
10 1 32 1 incomplete list 1 new designs [2]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
12 1 32 1 declined list 3 build orders [0]
|
||||||
|
ship construction: no phase in this engine builds a ship, so the build queue's ordinal, the maintenance charge, the savings debit and the hull's id allocation all have no model
|
||||||
|
12 1 32 1 declined list 3 build orders [1]
|
||||||
|
ship construction: no phase in this engine builds a ship, so the build queue's ordinal, the maintenance charge, the savings debit and the hull's id allocation all have no model
|
||||||
|
12 1 32 1 declined list 3 build orders [2]
|
||||||
|
ship construction: no phase in this engine builds a ship, so the build queue's ordinal, the maintenance charge, the savings debit and the hull's id allocation all have no model
|
||||||
|
12 1 32 1 declined list 3 build orders [3]
|
||||||
|
ship construction: no phase in this engine builds a ship, so the build queue's ordinal, the maintenance charge, the savings debit and the hull's id allocation all have no model
|
||||||
|
12 1 32 1 declined list 3 build orders [4]
|
||||||
|
ship construction: no phase in this engine builds a ship, so the build queue's ordinal, the maintenance charge, the savings debit and the hull's id allocation all have no model
|
||||||
|
12 1 32 1 declined list 3 build orders [5]
|
||||||
|
ship construction: no phase in this engine builds a ship, so the build queue's ordinal, the maintenance charge, the savings debit and the hull's id allocation all have no model
|
||||||
|
12 1 32 1 declined list 3 build orders [6]
|
||||||
|
ship construction: no phase in this engine builds a ship, so the build queue's ordinal, the maintenance charge, the savings debit and the hull's id allocation all have no model
|
||||||
|
12 1 32 1 declined list 3 build orders [7]
|
||||||
|
ship construction: no phase in this engine builds a ship, so the build queue's ordinal, the maintenance charge, the savings debit and the hull's id allocation all have no model
|
||||||
|
12 1 32 1 declined list 3 build orders [8]
|
||||||
|
ship construction: no phase in this engine builds a ship, so the build queue's ordinal, the maintenance charge, the savings debit and the hull's id allocation all have no model
|
||||||
|
12 1 32 1 declined list 3 build orders [9]
|
||||||
|
ship construction: no phase in this engine builds a ship, so the build queue's ordinal, the maintenance charge, the savings debit and the hull's id allocation all have no model
|
||||||
|
12 1 32 1 declined list 3 build orders [10]
|
||||||
|
ship construction: no phase in this engine builds a ship, so the build queue's ordinal, the maintenance charge, the savings debit and the hull's id allocation all have no model
|
||||||
|
12 1 32 1 declined list 3 build orders [11]
|
||||||
|
ship construction: no phase in this engine builds a ship, so the build queue's ordinal, the maintenance charge, the savings debit and the hull's id allocation all have no model
|
||||||
|
12 1 32 1 declined list 3 build orders [12]
|
||||||
|
ship construction: no phase in this engine builds a ship, so the build queue's ordinal, the maintenance charge, the savings debit and the hull's id allocation all have no model
|
||||||
|
12 1 32 1 declined list 3 build orders [13]
|
||||||
|
ship construction: no phase in this engine builds a ship, so the build queue's ordinal, the maintenance charge, the savings debit and the hull's id allocation all have no model
|
||||||
|
12 1 32 1 declined list 3 build orders [14]
|
||||||
|
ship construction: no phase in this engine builds a ship, so the build queue's ordinal, the maintenance charge, the savings debit and the hull's id allocation all have no model
|
||||||
|
12 1 32 1 declined list 3 build orders [15]
|
||||||
|
ship construction: no phase in this engine builds a ship, so the build queue's ordinal, the maintenance charge, the savings debit and the hull's id allocation all have no model
|
||||||
|
12 1 32 1 declined list 3 build orders [16]
|
||||||
|
ship construction: no phase in this engine builds a ship, so the build queue's ordinal, the maintenance charge, the savings debit and the hull's id allocation all have no model
|
||||||
|
12 1 32 1 declined list 3 build orders [17]
|
||||||
|
ship construction: no phase in this engine builds a ship, so the build queue's ordinal, the maintenance charge, the savings debit and the hull's id allocation all have no model
|
||||||
|
12 1 32 1 declined list 3 build orders [18]
|
||||||
|
ship construction: no phase in this engine builds a ship, so the build queue's ordinal, the maintenance charge, the savings debit and the hull's id allocation all have no model
|
||||||
|
17 1 32 1 declined list 10 [0]
|
||||||
|
an unnamed command; its three words fit 'assign these ships to this fleet at this system' and that reading has never been tested
|
||||||
|
17 1 32 1 declined list 10 [1]
|
||||||
|
an unnamed command; its three words fit 'assign these ships to this fleet at this system' and that reading has never been tested
|
||||||
|
17 1 32 1 declined list 10 [2]
|
||||||
|
an unnamed command; its three words fit 'assign these ships to this fleet at this system' and that reading has never been tested
|
||||||
|
17 1 32 1 declined list 10 [3]
|
||||||
|
an unnamed command; its three words fit 'assign these ships to this fleet at this system' and that reading has never been tested
|
||||||
|
18 1 32 1 incomplete list 12 fleet layouts [0]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
18 1 32 1 incomplete list 12 fleet layouts [1]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
18 1 32 1 incomplete list 12 fleet layouts [2]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
18 1 32 1 incomplete list 12 fleet layouts [3]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
18 1 32 1 incomplete list 12 fleet layouts [4]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
18 1 32 1 incomplete list 12 fleet layouts [5]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
18 1 32 1 incomplete list 12 fleet layouts [6]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
18 1 32 1 incomplete list 12 fleet layouts [7]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
18 1 32 1 incomplete list 12 fleet layouts [8]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
18 1 32 1 incomplete list 12 fleet layouts [9]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
18 1 32 1 incomplete list 12 fleet layouts [10]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
18 1 32 1 incomplete list 12 fleet layouts [11]
|
||||||
|
the capture recorded this element's presence but not all of its payload; the command is counted and deliberately not applied
|
||||||
|
20 1 32 1 declined list 14 fleet tasks [0]
|
||||||
|
a fleet task keyed on (fleet, mode); the two modes' effects are unread, and the fleet it names is the client-allocated one from list 8
|
||||||
|
20 1 32 1 declined list 14 fleet tasks [1]
|
||||||
|
a fleet task keyed on (fleet, mode); the two modes' effects are unread, and the fleet it names is the client-allocated one from list 8
|
||||||
|
20 1 32 1 declined list 14 fleet tasks [2]
|
||||||
|
a fleet task keyed on (fleet, mode); the two modes' effects are unread, and the fleet it names is the client-allocated one from list 8
|
||||||
|
20 1 32 1 declined list 14 fleet tasks [3]
|
||||||
|
a fleet task keyed on (fleet, mode); the two modes' effects are unread, and the fleet it names is the client-allocated one from list 8
|
||||||
|
20 1 32 1 declined list 14 fleet tasks [4]
|
||||||
|
a fleet task keyed on (fleet, mode); the two modes' effects are unread, and the fleet it names is the client-allocated one from list 8
|
||||||
|
20 1 32 1 declined list 14 fleet tasks [5]
|
||||||
|
a fleet task keyed on (fleet, mode); the two modes' effects are unread, and the fleet it names is the client-allocated one from list 8
|
||||||
|
20 1 32 1 declined list 14 fleet tasks [6]
|
||||||
|
a fleet task keyed on (fleet, mode); the two modes' effects are unread, and the fleet it names is the client-allocated one from list 8
|
||||||
|
20 1 32 1 declined list 14 fleet tasks [7]
|
||||||
|
a fleet task keyed on (fleet, mode); the two modes' effects are unread, and the fleet it names is the client-allocated one from list 8
|
||||||
|
23 1 32 1 declined list 7 colonize [0]
|
||||||
|
colonisation from a named colony ship: the colony formulas exist but the ship-to-planet resolution the command relies on does not
|
||||||
|
23 1 32 1 declined list 7 colonize [1]
|
||||||
|
colonisation from a named colony ship: the colony formulas exist but the ship-to-planet resolution the command relies on does not
|
||||||
|
24 1 32 1 declined list 8 fleet moves [0]
|
||||||
|
the order names a fleet the input save does not contain -- the client allocates the fleet object AND its id before it submits, and that allocator is unread, so applying a route would move a fleet that does not exist
|
||||||
|
24 1 32 1 declined list 8 fleet moves [1]
|
||||||
|
the order names a fleet the input save does not contain -- the client allocates the fleet object AND its id before it submits, and that allocator is unread, so applying a route would move a fleet that does not exist
|
||||||
|
24 1 32 1 declined list 8 fleet moves [2]
|
||||||
|
the order names a fleet the input save does not contain -- the client allocates the fleet object AND its id before it submits, and that allocator is unread, so applying a route would move a fleet that does not exist
|
||||||
|
|
||||||
|
phases
|
||||||
|
turn drivers (the milestone's denominator): 16 of 44 modelled, 12 committed
|
||||||
|
verified 0 implemented 4 partial 8 blocked 4 stub 28
|
||||||
|
post-combat tail (written to the autosave, tracked separately): 6 of 37 modelled
|
||||||
|
verified 0 implemented 1 partial 4 blocked 1 stub 31
|
||||||
|
|
||||||
|
this run
|
||||||
|
leaves written 96
|
||||||
|
leaves NOT written by a blocked phase 119
|
||||||
|
generator words consumed 16 (state loaded, left untouched)
|
||||||
|
generator words NOT accounted (never netted off the above):
|
||||||
|
- encounter detection draws one unit value and one bounded integer per turn on every turn measured (2 words), with no derived rule behind the count -- its bound is the product of the contact and detector counts, so it is left unmodelled
|
||||||
|
- two draws are downstream of the budget's research allocation -- ProcessResearch's completion Chance and the tech-effect callback's own roll (0 or 1 word each). The allocation needs ComputeBudget's per-system money, which is ComputeOutput with the system's OWN rate sliders; the max-income form of that money is now modelled and self-checked (see T31), but it is NOT the one this path takes
|
||||||
|
- a successful raid roll may draw one further word to pick its target; no roll succeeded on any measured turn, so the cost of a success is 0 or 1 and undetermined
|
||||||
|
! the generator advanced during this run but the save keeps its original state (--commit-rng to write it)
|
||||||
|
! the modelled words are a LOWER BOUND on the turn's cost, so a committed generator is short by the unaccounted sites below and its drawn VALUES are not the game's
|
||||||
|
|
||||||
|
wrote r1-deep.sav (100615 bytes gzipped, 1052288 inflated)
|
||||||
|
metric -> r1.json
|
||||||
1096
verify/results/standalone/cv/cv-replay-vs-bp-pinB.txt
Normal file
1096
verify/results/standalone/cv/cv-replay-vs-bp-pinB.txt
Normal file
File diff suppressed because it is too large
Load diff
141
verify/results/turncommands/br2-turn27-deep.tcb
Normal file
141
verify/results/turncommands/br2-turn27-deep.tcb
Normal file
|
|
@ -0,0 +1,141 @@
|
||||||
|
tcb 1
|
||||||
|
meta source BR2-deep-aiorders.txt
|
||||||
|
meta input ad-turn27-two-raiders.sav
|
||||||
|
meta batch seq=2 n=8
|
||||||
|
meta note the load-time batch is excluded; this is the End-Turn submission
|
||||||
|
seed 32 0x156ebbbd
|
||||||
|
seed 496 0xfe7b2826
|
||||||
|
seed 512 0x0ed341d1
|
||||||
|
block 0 16
|
||||||
|
gate 0 rate 1
|
||||||
|
block 1 32
|
||||||
|
gate 1 rate 0.8
|
||||||
|
list 1 1 3
|
||||||
|
elem 1 1 0 ?
|
||||||
|
# observed list 1 elem 0 word 2 string: Egg Thief Mk 4
|
||||||
|
elem 1 1 1 ?
|
||||||
|
# observed list 1 elem 1 word 2 string: Egg Thief Mk 5
|
||||||
|
elem 1 1 2 ?
|
||||||
|
# observed list 1 elem 2 word 2 string: Bravestar Mk 3
|
||||||
|
list 1 3 19
|
||||||
|
elem 1 3 0 i291 i962 i384 i0
|
||||||
|
elem 1 3 1 i292 i962 i384 i0
|
||||||
|
elem 1 3 2 i293 i962 i384 i0
|
||||||
|
elem 1 3 3 i294 i962 i384 i0
|
||||||
|
elem 1 3 4 i295 i962 i384 i0
|
||||||
|
elem 1 3 5 i296 i962 i384 i0
|
||||||
|
elem 1 3 6 i297 i962 i272 i0
|
||||||
|
elem 1 3 7 i298 i962 i272 i0
|
||||||
|
elem 1 3 8 i299 i962 i272 i0
|
||||||
|
elem 1 3 9 i300 i962 i272 i0
|
||||||
|
elem 1 3 10 i301 i962 i272 i0
|
||||||
|
elem 1 3 11 i302 i962 i368 i0
|
||||||
|
elem 1 3 12 i303 i962 i368 i0
|
||||||
|
# observed list 3 elem 12 word 6 vector: []
|
||||||
|
elem 1 3 13 i304 i1490 i368 i0
|
||||||
|
elem 1 3 14 i305 i1474 i368 i0
|
||||||
|
elem 1 3 15 i306 i1826 i464 i0
|
||||||
|
elem 1 3 16 i307 i1826 i464 i0
|
||||||
|
elem 1 3 17 i308 i1826 i464 i0
|
||||||
|
elem 1 3 18 i309 i1522 i80 i0
|
||||||
|
list 1 5 15
|
||||||
|
elem 1 5 0 i464 ? ? ? ? ? ? ?
|
||||||
|
elem 1 5 1 i80 ? ? ? ? ? ? ?
|
||||||
|
elem 1 5 2 i160 ? ? ? ? ? ? ?
|
||||||
|
elem 1 5 3 i192 ? ? ? ? ? ? ?
|
||||||
|
elem 1 5 4 i272 ? ? ? ? ? ? ?
|
||||||
|
elem 1 5 5 i288 ? ? ? ? ? ? ?
|
||||||
|
elem 1 5 6 i304 ? ? ? ? ? ? ?
|
||||||
|
elem 1 5 7 i336 ? ? ? ? ? ? ?
|
||||||
|
elem 1 5 8 i352 ? ? ? ? ? ? ?
|
||||||
|
elem 1 5 9 i368 ? ? ? ? ? ? ?
|
||||||
|
elem 1 5 10 i384 ? ? ? ? ? ? ?
|
||||||
|
elem 1 5 11 i400 ? ? ? ? ? ? ?
|
||||||
|
elem 1 5 12 i416 ? ? ? ? ? ? ?
|
||||||
|
elem 1 5 13 i432 ? ? ? ? ? ? ?
|
||||||
|
elem 1 5 14 i448 ? ? ? ? ? ? ?
|
||||||
|
list 1 7 2
|
||||||
|
elem 1 7 0 i5904 i0
|
||||||
|
elem 1 7 1 i6016 i1
|
||||||
|
list 1 8 3
|
||||||
|
elem 1 8 0 i2002 v1:256
|
||||||
|
elem 1 8 1 i1970 v1:384
|
||||||
|
elem 1 8 2 i1538 v1:240
|
||||||
|
list 1 10 4
|
||||||
|
elem 1 10 0 i80 i1970 v1:5264
|
||||||
|
elem 1 10 1 i384 i1986 v1:6976
|
||||||
|
elem 1 10 2 i384 i2002 v1:6992
|
||||||
|
elem 1 10 3 i816 i7072 v11:2992,3456,4304,4912,5680,3184,5856,6000,6256,6464,2720
|
||||||
|
list 1 12 12
|
||||||
|
elem 1 12 0 ?
|
||||||
|
# observed list 12 elem 0 word 6 vector: [2544,2896,2528]
|
||||||
|
elem 1 12 1 ?
|
||||||
|
# observed list 12 elem 1 word 6 vector: [2128,2144,3072,1872,1888,1904,2400,2800,3008,3040,3056,2384,2752,2416,2160]
|
||||||
|
elem 1 12 2 ?
|
||||||
|
# observed list 12 elem 2 word 6 vector: [2288]
|
||||||
|
elem 1 12 3 ?
|
||||||
|
# observed list 12 elem 3 word 6 vector: [2080,2672,2704,2320,1856]
|
||||||
|
elem 1 12 4 ?
|
||||||
|
# observed list 12 elem 4 word 6 vector: [3152,3136,2960,3408]
|
||||||
|
elem 1 12 5 ?
|
||||||
|
# observed list 12 elem 5 word 6 vector: [3504,3472,3488,3216,3264,3520]
|
||||||
|
elem 1 12 6 ?
|
||||||
|
# observed list 12 elem 6 word 6 vector: [2224,4000,4400,3536,3552,3568,1664,1920,3280,3296,3312,3968,3984,1952,2832,2864,3104,3120,2848,2880]
|
||||||
|
elem 1 12 7 ?
|
||||||
|
# observed list 12 elem 7 word 6 vector: [4240,4864,4640,4544,4560,4576,4592,4624,4160,4880,4896,3920,3952,4368,4384,4192,4224,4848,4608,4208,4656,4784]
|
||||||
|
elem 1 12 8 ?
|
||||||
|
# observed list 12 elem 8 word 6 vector: [6368,6384,4416,4432,4464,4768,3632,4016,4048,4032,3616]
|
||||||
|
elem 1 12 9 ?
|
||||||
|
# observed list 12 elem 9 word 6 vector: [3696,4512,4816,4080,3712,4112,4800]
|
||||||
|
elem 1 12 10 ?
|
||||||
|
# observed list 12 elem 10 word 6 vector: [6272]
|
||||||
|
elem 1 12 11 ?
|
||||||
|
# observed list 12 elem 11 word 6 vector: [6432,6224,6400,6192,6240,6448,6416]
|
||||||
|
list 1 14 8
|
||||||
|
elem 1 14 0 i1970 i0 b1
|
||||||
|
elem 1 14 1 i1970 i1 b1
|
||||||
|
elem 1 14 2 i1986 i0 b1
|
||||||
|
elem 1 14 3 i1986 i1 b1
|
||||||
|
elem 1 14 4 i2002 i0 b1
|
||||||
|
elem 1 14 5 i2002 i1 b1
|
||||||
|
elem 1 14 6 i7072 i0 b1
|
||||||
|
elem 1 14 7 i7072 i1 b1
|
||||||
|
list 1 23 15
|
||||||
|
elem 1 23 0 i464 ?
|
||||||
|
# observed list 23 elem 0 word 2 vector: [12422480,1,2,0,1000000000,0]
|
||||||
|
elem 1 23 1 i80 ?
|
||||||
|
# observed list 23 elem 1 word 2 vector: [12422480,1,2,1,600000000,0]
|
||||||
|
elem 1 23 2 i160 ?
|
||||||
|
# observed list 23 elem 2 word 2 vector: [12422480,1,2,80,800000000,0]
|
||||||
|
elem 1 23 3 i192 ?
|
||||||
|
# observed list 23 elem 3 word 2 vector: [12422480,1,2,272,300000000,0]
|
||||||
|
elem 1 23 4 i272 ?
|
||||||
|
# observed list 23 elem 4 word 2 vector: [12422480,1,2,0,400000000,0]
|
||||||
|
elem 1 23 5 i288 ?
|
||||||
|
# observed list 23 elem 5 word 2 vector: [12422480,1,2,384,700000000,0]
|
||||||
|
elem 1 23 6 i304 ?
|
||||||
|
# observed list 23 elem 6 word 2 vector: [12422480,1,2,464,100000000,0]
|
||||||
|
elem 1 23 7 i336 ?
|
||||||
|
# observed list 23 elem 7 word 2 vector: [12422480,1,2,0,200000000,0]
|
||||||
|
elem 1 23 8 i352 ?
|
||||||
|
# observed list 23 elem 8 word 2 vector: [12422480,1,2,272,500000000,0]
|
||||||
|
elem 1 23 9 i368 ?
|
||||||
|
# observed list 23 elem 9 word 2 vector: [12422480,1,2,368,700000000,0]
|
||||||
|
elem 1 23 10 i384 ?
|
||||||
|
# observed list 23 elem 10 word 2 vector: [12422480,1,2,368,800000000,0]
|
||||||
|
elem 1 23 11 i400 ?
|
||||||
|
# observed list 23 elem 11 word 2 vector: [12422480,1,2,0,400000000,0]
|
||||||
|
elem 1 23 12 i416 ?
|
||||||
|
# observed list 23 elem 12 word 2 vector: [12422480,1,2,0,500000000,0]
|
||||||
|
elem 1 23 13 i432 ?
|
||||||
|
# observed list 23 elem 13 word 2 vector: [12422480,1,2,368,400000000,0]
|
||||||
|
elem 1 23 14 i448 ?
|
||||||
|
# observed list 23 elem 14 word 2 vector: [12422480,1,2,368,500000000,0]
|
||||||
|
block 2 496
|
||||||
|
gate 2 rate 0.8
|
||||||
|
block 3 512
|
||||||
|
gate 3 rate 0.8
|
||||||
|
block 4 0
|
||||||
|
block 5 0
|
||||||
|
block 6 0
|
||||||
|
block 7 0
|
||||||
110
verify/results/turncommands/br2-turn27-shallow.tcb
Normal file
110
verify/results/turncommands/br2-turn27-shallow.tcb
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
tcb 1
|
||||||
|
meta source BR2-deep-aiorders.txt
|
||||||
|
meta input ad-turn27-two-raiders.sav
|
||||||
|
meta batch seq=2 n=8
|
||||||
|
meta note the load-time batch is excluded; this is the End-Turn submission
|
||||||
|
seed 32 0x156ebbbd
|
||||||
|
seed 496 0xfe7b2826
|
||||||
|
seed 512 0x0ed341d1
|
||||||
|
block 0 16
|
||||||
|
gate 0 rate 1
|
||||||
|
block 1 32
|
||||||
|
gate 1 rate 0.8
|
||||||
|
list 1 1 3
|
||||||
|
elem 1 1 0 ?
|
||||||
|
elem 1 1 1 ?
|
||||||
|
elem 1 1 2 ?
|
||||||
|
list 1 3 19
|
||||||
|
elem 1 3 0 i291 i962 i384 i0
|
||||||
|
elem 1 3 1 i292 i962 i384 i0
|
||||||
|
elem 1 3 2 i293 i962 i384 i0
|
||||||
|
elem 1 3 3 i294 i962 i384 i0
|
||||||
|
elem 1 3 4 i295 i962 i384 i0
|
||||||
|
elem 1 3 5 i296 i962 i384 i0
|
||||||
|
elem 1 3 6 i297 i962 i272 i0
|
||||||
|
elem 1 3 7 i298 i962 i272 i0
|
||||||
|
elem 1 3 8 i299 i962 i272 i0
|
||||||
|
elem 1 3 9 i300 i962 i272 i0
|
||||||
|
elem 1 3 10 i301 i962 i272 i0
|
||||||
|
elem 1 3 11 i302 i962 i368 i0
|
||||||
|
elem 1 3 12 i303 i962 i368 i0
|
||||||
|
elem 1 3 13 i304 i1490 i368 i0
|
||||||
|
elem 1 3 14 i305 i1474 i368 i0
|
||||||
|
elem 1 3 15 i306 i1826 i464 i0
|
||||||
|
elem 1 3 16 i307 i1826 i464 i0
|
||||||
|
elem 1 3 17 i308 i1826 i464 i0
|
||||||
|
elem 1 3 18 i309 i1522 i80 i0
|
||||||
|
list 1 5 15
|
||||||
|
elem 1 5 0 i464 ? ? ? ? ? ? ?
|
||||||
|
elem 1 5 1 i80 ? ? ? ? ? ? ?
|
||||||
|
elem 1 5 2 i160 ? ? ? ? ? ? ?
|
||||||
|
elem 1 5 3 i192 ? ? ? ? ? ? ?
|
||||||
|
elem 1 5 4 i272 ? ? ? ? ? ? ?
|
||||||
|
elem 1 5 5 i288 ? ? ? ? ? ? ?
|
||||||
|
elem 1 5 6 i304 ? ? ? ? ? ? ?
|
||||||
|
elem 1 5 7 i336 ? ? ? ? ? ? ?
|
||||||
|
elem 1 5 8 i352 ? ? ? ? ? ? ?
|
||||||
|
elem 1 5 9 i368 ? ? ? ? ? ? ?
|
||||||
|
elem 1 5 10 i384 ? ? ? ? ? ? ?
|
||||||
|
elem 1 5 11 i400 ? ? ? ? ? ? ?
|
||||||
|
elem 1 5 12 i416 ? ? ? ? ? ? ?
|
||||||
|
elem 1 5 13 i432 ? ? ? ? ? ? ?
|
||||||
|
elem 1 5 14 i448 ? ? ? ? ? ? ?
|
||||||
|
list 1 7 2
|
||||||
|
elem 1 7 0 i5904 i0
|
||||||
|
elem 1 7 1 i6016 i1
|
||||||
|
list 1 8 3
|
||||||
|
elem 1 8 0 i2002 v1
|
||||||
|
elem 1 8 1 i1970 v1
|
||||||
|
elem 1 8 2 i1538 v1
|
||||||
|
list 1 10 4
|
||||||
|
elem 1 10 0 i80 i1970 v1
|
||||||
|
elem 1 10 1 i384 i1986 v1
|
||||||
|
elem 1 10 2 i384 i2002 v1
|
||||||
|
elem 1 10 3 i816 i7072 v11
|
||||||
|
list 1 12 12
|
||||||
|
elem 1 12 0 ?
|
||||||
|
elem 1 12 1 ?
|
||||||
|
elem 1 12 2 ?
|
||||||
|
elem 1 12 3 ?
|
||||||
|
elem 1 12 4 ?
|
||||||
|
elem 1 12 5 ?
|
||||||
|
elem 1 12 6 ?
|
||||||
|
elem 1 12 7 ?
|
||||||
|
elem 1 12 8 ?
|
||||||
|
elem 1 12 9 ?
|
||||||
|
elem 1 12 10 ?
|
||||||
|
elem 1 12 11 ?
|
||||||
|
list 1 14 8
|
||||||
|
elem 1 14 0 i1970 i0 b1
|
||||||
|
elem 1 14 1 i1970 i1 b1
|
||||||
|
elem 1 14 2 i1986 i0 b1
|
||||||
|
elem 1 14 3 i1986 i1 b1
|
||||||
|
elem 1 14 4 i2002 i0 b1
|
||||||
|
elem 1 14 5 i2002 i1 b1
|
||||||
|
elem 1 14 6 i7072 i0 b1
|
||||||
|
elem 1 14 7 i7072 i1 b1
|
||||||
|
list 1 23 15
|
||||||
|
elem 1 23 0 i464 ?
|
||||||
|
elem 1 23 1 i80 ?
|
||||||
|
elem 1 23 2 i160 ?
|
||||||
|
elem 1 23 3 i192 ?
|
||||||
|
elem 1 23 4 i272 ?
|
||||||
|
elem 1 23 5 i288 ?
|
||||||
|
elem 1 23 6 i304 ?
|
||||||
|
elem 1 23 7 i336 ?
|
||||||
|
elem 1 23 8 i352 ?
|
||||||
|
elem 1 23 9 i368 ?
|
||||||
|
elem 1 23 10 i384 ?
|
||||||
|
elem 1 23 11 i400 ?
|
||||||
|
elem 1 23 12 i416 ?
|
||||||
|
elem 1 23 13 i432 ?
|
||||||
|
elem 1 23 14 i448 ?
|
||||||
|
block 2 496
|
||||||
|
gate 2 rate 0.8
|
||||||
|
block 3 512
|
||||||
|
gate 3 rate 0.8
|
||||||
|
block 4 0
|
||||||
|
block 5 0
|
||||||
|
block 6 0
|
||||||
|
block 7 0
|
||||||
Loading…
Add table
Reference in a new issue