Compare commits
2 commits
0a48be7498
...
9e39b0051a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e39b0051a | ||
|
|
d98f435017 |
3 changed files with 199 additions and 20 deletions
|
|
@ -1,20 +1,20 @@
|
|||
# SotS RE campaign — coverage dashboard
|
||||
|
||||
Generated 2026-09-09 00:58 UTC · `sots-re` @ 429f754,2026-09-08 · `sots-engine` @ b1c61a8,2026-09-08 (232 commits) · regenerate with `tools/dashboard.py`
|
||||
Generated 2026-09-09 01:59 UTC · `sots-re` @ d98f435,2026-09-08 · `sots-engine` @ e62d974,2026-09-08 (238 commits) · regenerate with `tools/dashboard.py`
|
||||
|
||||
> **North star:** A functional reimplementation of the engine — behavior-equivalent, NOT byte-for-byte
|
||||
|
||||
## 1. Map coverage (campaign/board.md)
|
||||
|
||||
389 targets · mapped-or-better **345/389** `[█████████░] 89%` · verified **303/389** `[████████░░] 78%`
|
||||
403 targets · mapped-or-better **356/403** `[█████████░] 88%` · verified **314/403** `[████████░░] 78%`
|
||||
|
||||
| Status | Count | % |
|
||||
|---|---:|---:|
|
||||
| verified | 303 | 78% |
|
||||
| mapped | 42 | 11% |
|
||||
| verified | 314 | 78% |
|
||||
| mapped | 42 | 10% |
|
||||
| in-progress | 4 | 1% |
|
||||
| backlog | 38 | 10% |
|
||||
| blocked | 2 | 1% |
|
||||
| backlog | 41 | 10% |
|
||||
| blocked | 2 | 0% |
|
||||
|
||||
| Type | verified | mapped | in-progress | backlog | blocked | total |
|
||||
|---|---:|---:|---:|---:|---:|---:|
|
||||
|
|
@ -22,24 +22,25 @@ Generated 2026-09-09 00:58 UTC · `sots-re` @ 429f754,2026-09-08 · `sots-engine
|
|||
| control-flow | 24 | 2 | 0 | 0 | 0 | 26 |
|
||||
| subsystems | 4 | 8 | 0 | 2 | 1 | 15 |
|
||||
| engine | 29 | 0 | 0 | 0 | 0 | 29 |
|
||||
| verify | 94 | 15 | 3 | 32 | 0 | 144 |
|
||||
| verify | 101 | 15 | 3 | 35 | 0 | 154 |
|
||||
| phase2 | 13 | 3 | 1 | 0 | 0 | 17 |
|
||||
| meta | 74 | 6 | 0 | 1 | 0 | 81 |
|
||||
| meta | 78 | 6 | 0 | 1 | 0 | 85 |
|
||||
| other | 19 | 2 | 0 | 0 | 0 | 21 |
|
||||
|
||||
## 2. Binary understanding
|
||||
|
||||
- RTTI type descriptors: **1,924** (`Game::` 1,404, `Mars::` 194; serializable types 179)
|
||||
- Classes with recovered member layouts: **384** / 1,598 named classes `[██░░░░░░░░] 24%` — `objects/layouts.json` (serializer recovery) plus classes recovered by hand in `struct-recovery.md` + `schema-gaps-resolved.md`. Note 179 types are *serializable*; the recovery also reaches non-serializable ones, so this is not a subset of that
|
||||
- Functions: **41,411** (parsed from `01-fingerprint.md`); named/annotated in the **address contract** (`ghidra/addresses.json`, not Ghidra's full rename count): **1241**, verified **1122** `[█████████░] 90%`
|
||||
- Functions: **41,411** (parsed from `01-fingerprint.md`); named/annotated in the **address contract** (`ghidra/addresses.json`, not Ghidra's full rename count): **1247**, verified **1122** `[█████████░] 90%`
|
||||
|
||||
## 3. Data layer
|
||||
|
||||
- Catalogs: **1,595/1,595** files parsed (91 block kinds in `schema_stats.json`), dangling cross-refs **0** (`crosslink.json`)
|
||||
- Oracle `mars-parse`: **1,531/1,531** files agree `[██████████] 100%`
|
||||
- Oracle `mars-text`: **64/64** files agree `[██████████] 100%`
|
||||
- Saves: **20/20** real saves strict-clean — strict exit 0, 0 errors, 0 warnings
|
||||
- Saves: **22/22** real saves strict-clean — strict exit 0, 0 errors, 0 warnings
|
||||
- Design rules: **127/127** stock designs pass `[██████████] 100%`
|
||||
- Value domains: **490/724** typed fields have been seen to vary `[███████░░░] 68%` — the other **234** have only ever held one value across the corpus, so their typing is untested (`value-domain-census.md`)
|
||||
|
||||
## 4. Engine accrual (sots-engine)
|
||||
|
||||
|
|
@ -57,13 +58,13 @@ Generated 2026-09-09 00:58 UTC · `sots-re` @ 429f754,2026-09-08 · `sots-engine
|
|||
| `game/sim` | 4,780 | 14 | 1038 | yes | game-sim.md |
|
||||
| `mars/parse` | 875 | 12 | 277 | yes | mars-parse.md |
|
||||
| `mars/rng` | 244 | 0 | 0 | yes | mars-rng.md |
|
||||
| `mars/stream` | 5,671 | 7 | 313 | yes | mars-stream.md |
|
||||
| `mars/stream` | 5,834 | 8 | 316 | yes | mars-stream.md |
|
||||
| `mars/text` | 899 | 8 | 245 | yes | mars-text.md |
|
||||
| `mars/vfs` | 788 | 9 | 140 | yes | mars-vfs.md |
|
||||
| `shim` | 16,284 | 0 | 0 | direct (WIN32) | H-probes.md |
|
||||
| `shim/hooks` | 13,178 | 0 | 0 | direct (WIN32) | L1-predictions.md |
|
||||
| `shim` | 16,295 | 0 | 0 | direct (WIN32) | H-probes.md |
|
||||
| `shim/hooks` | 13,189 | 0 | 0 | direct (WIN32) | L1-predictions.md |
|
||||
| `shim/trace` | 2,258 | 9 | 273 | direct (WIN32) | shim-trace.md |
|
||||
| **total** | **58,433** | **121** | **4241** | | |
|
||||
| **total** | **58,618** | **122** | **4244** | | |
|
||||
|
||||
Board `engine:` rows: verified **29**, mapped 0, in flight 0 (of 29) — verified & merged `[██████████] 100%`
|
||||
|
||||
|
|
@ -111,7 +112,7 @@ Detail: `verify/results/standalone/report.txt`.
|
|||
|
||||
## 7. Verification ledger
|
||||
|
||||
- ✅ Saves strict: 20/20 (strict exit 0, 0 errors, 0 warnings)
|
||||
- ✅ Saves strict: 22/22 (strict exit 0, 0 errors, 0 warnings)
|
||||
- ✅ Design rules: 127/127
|
||||
- ✅ oracle mars-parse 1531/1531 · ✅ oracle mars-text 64/64
|
||||
- ✅ Compare harness present (`verify/harness/compare/`)
|
||||
|
|
@ -132,11 +133,11 @@ Most recent open:
|
|||
|
||||
## 9. Delta since previous dashboard
|
||||
|
||||
- verified targets: 291 → 303 (+12) · mapped-or-better: 333 → 345 (+12)
|
||||
- engine LOC: 57,699 → 58,433 (+734) · test files: 121 → 121 (+0) · checks: 4,241 → 4,241 (+0)
|
||||
- addresses verified: 1,121 → 1,122 (+1) · recovered layouts: 384 → 384 (+0) · open questions: 26 → 26 (+0)
|
||||
- verified targets: 314 → 314 (+0) · mapped-or-better: 356 → 356 (+0)
|
||||
- engine LOC: 58,618 → 58,618 (+0) · test files: 122 → 122 (+0) · checks: 4,244 → 4,244 (+0)
|
||||
- addresses verified: 1,122 → 1,122 (+0) · recovered layouts: 384 → 384 (+0) · open questions: 26 → 26 (+0)
|
||||
- standalone leaves closed: 45 → 45 (+0) · leaves still diverging: 63 → 63 (+0)
|
||||
|
||||
---
|
||||
warnings: board.md: unknown types subsystems; 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": 303, "mapped_plus": 345, "targets": 389, "loc": 58433, "tests": 121, "checks": 4241, "addr_verified": 1122, "addr_total": 1241, "layouts": 384, "open_q": 26, "sa_closed": 45, "sa_left": 63} -->
|
||||
<!-- dashboard-metrics {"verified": 314, "mapped_plus": 356, "targets": 403, "loc": 58618, "tests": 122, "checks": 4244, "addr_verified": 1122, "addr_total": 1247, "layouts": 384, "open_q": 26, "sa_closed": 45, "sa_left": 63} -->
|
||||
|
|
|
|||
163
findings/control-flow/raid-gate-multiplicity.md
Normal file
163
findings/control-flow/raid-gate-multiplicity.md
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
# Trade-raid gate multiplicity — does the tail draw once per turn, or once per qualifying fleet?
|
||||
|
||||
- **Type:** control-flow (static decode + live measurement)
|
||||
- **Status:** **predictions committed, not yet measured** — this header block is replaced when the
|
||||
run lands
|
||||
- **Owner / date:** lane AD · 2026-09-08 · guest **VM141** (`sots-re-win10-b`, 192.168.10.143)
|
||||
- **Follows:** the resolution `findings/resolutions/2026-09-09-tail-draws.md` §4 (the one probe),
|
||||
lane AC's `findings/control-flow/trade-raid-rng-gate.md`
|
||||
- **Instrument:** lane Z's return-address ledger (`draw_sites`) + lane H's entry probes at
|
||||
**`probes=8`** — the configuration lane H bisected as byte-neutral. **Not `probes=11`.**
|
||||
|
||||
---
|
||||
|
||||
## 1. Predictions, committed before the build (rule 2)
|
||||
|
||||
Written on the host, before the shim was built, before the workload was played and before any
|
||||
counter was read. What follows in §1 is frozen; everything after it is the run.
|
||||
|
||||
### 1.0 The callee, decoded in full first
|
||||
|
||||
Lane AC read the *caller* (`ServerTradeManagerImpl::vslot13`, `0x0088ef80`) and reported the
|
||||
short-circuit inside the callee from a partial read. This lane decompiled the whole of
|
||||
`TradeManager::Slot13RngCalleeA` `0x00820ca0` (436 bytes, 89 decompiled lines, both the loop and
|
||||
its converge point visible — rule 4), because the prediction depends on where the draw sits
|
||||
relative to the loop. Transcribed to a model:
|
||||
|
||||
```
|
||||
A(fleet, freighterInSector) -> bool:
|
||||
if fleet == null: return false # 0 words
|
||||
n = (fleet+0xa8 - fleet+0xa4) / 4 # ship vector count
|
||||
if n <= 0: return false # 0 words
|
||||
anyBig = OR over ships of ( *(design + 0x12c) > 1 )
|
||||
allSuppressed= AND over ships of ( ship+0x18 & 0x80 )
|
||||
nDE = #{ ships : !(flags & 0x80) and *(design+0x12c) == 0 }
|
||||
nCR = #{ ships : !(flags & 0x80) and *(design+0x12c) == 1 }
|
||||
bestScale = max over ships of ( (flags & 0x100000) ? K : 1.0 ) # K a float global
|
||||
if anyBig: return TRUE # 0 words <-- short-circuit
|
||||
if allSuppressed: return false # 0 words
|
||||
odds = (nCR >= 1 ? ODDS_CR : (nDE > 0 ? ODDS_DE : 0.0)) + (nCR + nDE) * PER_SHIP
|
||||
if freighterInSector: odds = odds + odds
|
||||
r = NextFloat() # <-- EXACTLY ONE WORD
|
||||
return (odds * bestScale > r)
|
||||
```
|
||||
|
||||
Three consequences that the measurement is against:
|
||||
|
||||
1. **The draw is inside the callee, and the callee is called once per fleet.** So the word cost of
|
||||
the site is `Σ over fleets passing G0–G4 of (0 if short-circuited or shipless or all-suppressed,
|
||||
else 1)`. Not a per-sector constant.
|
||||
2. `design + 0x12c` takes the values **0, 1 and >1** and is used to bucket ships into two counted
|
||||
classes plus a third that short-circuits. That is a **hull class** field, and lane AC's fleet —
|
||||
one `Repair and Salvage`, built with `IND_CruisCon` — is the `== 1` bucket. `> 1` is therefore
|
||||
the next hull up (a dreadnought, if the ordering is DE/CR/DN), which this game has not
|
||||
researched.
|
||||
3. There is exactly **one** `NextFloat` on the path, with no rejection loop around it, so a fleet
|
||||
that reaches the roll costs exactly one word — never two.
|
||||
|
||||
### 1.1 The state this lane will build
|
||||
|
||||
From `verify/results/saves/ac-turn22-raider.sav`, read on the host before touching the guest:
|
||||
|
||||
| field | value read |
|
||||
|---|---|
|
||||
| player 0 | `PlryName "re"`, `PlyrIdx 0`, `HomeSys 48`, `Sav 63,032,174`, `CnRad true` |
|
||||
| player 0 fleets | **exactly one**: `FltID 3744` `"Alpha Fleet"` `PID 16`, `NShips 1`, `LocID 832`, `Pos [0, 0, 8.0]`, `FtFlg 4`, ship `DesID 17` (`Repair and Salvage`, `IND_CruisCon`) |
|
||||
| sector 6 | `TradeID 832`, `tsgridID 6`, `Pos [0, 0, 8.0]`, `tssec 0`, **`tsct 0`**, **`tscr 253`**, `tsnumsys 4` (`tssys` 256, 416, **48**, 96), `tsnumflt 1`, `tsflt 3744` |
|
||||
| all six sectors | `tscr 253` / `ptscr 253` |
|
||||
| player 0 designs | `Armor`, `Tanker`, `Colonizer`, `Extended Range`, `Light Defense Platform`, `Repair and Salvage` (`DesID 17`), `Default Assault Shuttle` |
|
||||
|
||||
Sector 6 contains the home system (48), `tsct` is 0 so the `FtFlg & 0x800` conjunct is not armed,
|
||||
and `tscr` bit 0 is set. Every conjunct of the gate is already satisfied for a **second** fleet
|
||||
parked on the same node.
|
||||
|
||||
**The workload:** build one more `Repair and Salvage` cruiser at system 48, keep it as its own
|
||||
fleet, order it to the sector-6 node, and confirm `LocID 832` + `Pos` bit-equality **from the
|
||||
autosave, not the panel** (lane AC's gotcha). That makes two single-cruiser fleets on one sector.
|
||||
|
||||
**Deliberate deviation from the brief, stated up front.** The brief and the resolution §4 ask for a
|
||||
second raider *of a hull satisfying `design+0x12c > 1`*, to price the short-circuit. §1.0 shows that
|
||||
field is a hull class and `> 1` means a hull above cruiser, which this game has not researched and
|
||||
cannot research and build inside five turns. Pricing the short-circuit is also the *second* question;
|
||||
the first is multiplicity, and a second **cruiser** answers it with the cleanest possible signal —
|
||||
under H-fleet the word count doubles, under H-sector it does not move. A dreadnought would leave the
|
||||
word count at 1 under both hypotheses and force the entry counter to carry the whole result alone.
|
||||
So: second cruiser, and the short-circuit stays unpriced. Recorded as a gap, not skipped.
|
||||
|
||||
### 1.2 P1 — H-fleet (primary)
|
||||
|
||||
**With two single-cruiser fleets on sector 6, `TradeManager::Slot13RngCalleeA` is entered `2` times
|
||||
per End Turn and `StrategyServer::OnAllCombatDone_Tail` costs `2` strategic words per turn**, against
|
||||
lane AC's `1` and `1` on the same lineage with one fleet.
|
||||
|
||||
Confidence: **high**, on §1.0 plus lane AC's read of the caller's loop over
|
||||
`StrategyServer+0x64..+0x68`.
|
||||
|
||||
*Falsification and symptom.* `calls = 1` on the `TradeManager::Slot13RngCalleeA` probe row with two
|
||||
fleets confirmed on the node kills it, and P2 is then the answer.
|
||||
|
||||
### 1.3 P2 — H-sector (the hypothesis this lane exists to kill)
|
||||
|
||||
If the roll is per *sector* and not per *fleet*, `Slot13RngCalleeA` is entered `1` time and the tail
|
||||
costs `1` word with two fleets exactly as with one.
|
||||
|
||||
Confidence: **low**. It is stated because four lanes have now been wrong about this call site by
|
||||
reasoning rather than measuring, and because a `1` here would mean §1.0's model — and therefore the
|
||||
generator model the standalone is about to gain — is wrong about the loop.
|
||||
|
||||
### 1.4 P3 — per-site attribution
|
||||
|
||||
`draw_sites` reports exactly **one** strategic-generator row inside the callee's body, entry kind
|
||||
`NextFloat`, `ret_rva` in `0x00420ca0..0x00420e53`, with `calls == words == 2` and
|
||||
`no_draw_calls == 0`. The site sum for the tail bracket equals the boundary ledger's tail delta.
|
||||
|
||||
Confidence: **high** on the row existing and on the equality; **moderate** on `calls == 2`, because
|
||||
that is P1 restated through the other instrument. The two instruments disagreeing is itself the
|
||||
interesting outcome and would be reported as one.
|
||||
|
||||
### 1.5 P4 — `Slot13RngCalleeB` and its inner `NextInt`
|
||||
|
||||
`B` is entered once per fleet whose roll **succeeded**, so `0`, `1` or `2` times per turn, and it
|
||||
costs **0 words** on every entry — i.e. **no** strategic `draw_sites` row inside
|
||||
`0x0048b440..0x0048b976`.
|
||||
|
||||
Confidence: **low-to-moderate**. "0 words" rests on lane AC's single observation and the resolution
|
||||
itself flags the gate above that `NextInt` as unread (§3.1's unfilled rows). A row appearing there is
|
||||
a **result**, not a failure: it prices a site the gate-indexed audit currently has to leave blank.
|
||||
|
||||
### 1.6 P5 — the oracle pair
|
||||
|
||||
Two `hooks=off` runs of the same End Turn from the same input save, in two fresh processes, produce
|
||||
**byte-identical** `(Autosave EndTurn).sav` and `(Autosave).sav`.
|
||||
|
||||
Confidence: **moderate, and this is the prediction most likely to fail.** Rule 26's counter-example
|
||||
is exactly this shape: three `hooks=off` runs on `turn1-state` gave three different files, pinned to
|
||||
a per-process AI seed. That save has three AI empires; this one has **seven**, at turn 22, all of
|
||||
them making research and build choices every turn. If the pair does not agree I will localise the
|
||||
difference to named leaves with the state-checksum tool, report whether it is confined to the known
|
||||
AI-seed leaves, and — if it is not — say plainly that **no oracle pair exists for this state** and
|
||||
that the numbers in §3 are entry counts and word deltas rather than calibration data. Rule 26: a
|
||||
control that does not agree with itself exonerates nothing.
|
||||
|
||||
### 1.7 P6 — instrument neutrality on this state (rule 19)
|
||||
|
||||
The `(Autosave).sav` produced by the `probes=8` run is byte-identical to the `hooks=off` oracle
|
||||
above. This is lane H's `probes=8` neutrality claim re-tested on a state it was never tested on,
|
||||
and it costs nothing to check because both files exist anyway.
|
||||
|
||||
Confidence: moderate. Conditional on P5: if the control does not agree with itself, this comparison
|
||||
means nothing and will not be reported as evidence (rule 26's second half — agreeing with one run of
|
||||
a varying control is a `1/k` coincidence).
|
||||
|
||||
### 1.8 What would make this lane report a zero (rule 28)
|
||||
|
||||
If `Slot13RngCalleeA` is entered `0` times, the failed conjunct will be named from the save, not
|
||||
guessed. The four to read on the post-move autosave are: `Flt.LocID == 832` for **both** fleets;
|
||||
`Flt.Pos` bit-equal to `Trade.Pos` `[0, 0, 8.0]` for both; `tscr` bit 0 still set (`253`); and
|
||||
`tsct` still `0` on sector 6 — because if the AI starts trading through sector 6 during the five
|
||||
turns, `tsct` bit 0 arms the `FtFlg & 0x800` conjunct and **both** fleets fail it, taking the site
|
||||
back to zero for a reason that has nothing to do with multiplicity.
|
||||
|
||||
---
|
||||
|
||||
*(Sections 2 onward are written after the run.)*
|
||||
|
|
@ -430,7 +430,22 @@ def render(engine, prev):
|
|||
if not oracles:
|
||||
L.append("- Oracle agreements: none parsed from `sots-engine/docs/mars-*.md`")
|
||||
L += [f"- Saves: **{nsaves}/{nsaves}** real saves strict-clean — {s_detail}" if s_ok else f"- Saves: {nsaves} real saves, strict **NOT clean** — {s_detail}",
|
||||
f"- Design rules: **{d_ok}/{d_tot}** stock designs pass {bar(d_ok or 0, d_tot or 1)}" if d_ok is not None else "- Design rules: ? (unparsed)", ""]
|
||||
f"- Design rules: **{d_ok}/{d_tot}** stock designs pass {bar(d_ok or 0, d_tot or 1)}" if d_ok is not None else "- Design rules: ? (unparsed)"]
|
||||
|
||||
# The counterweight to the 99.99% typed figure. Coverage is indexed by shape and
|
||||
# says nothing about whether a field was ever exercised; this is the value axis.
|
||||
# Parsed from the census findings file so there is one source of truth and it
|
||||
# goes visibly stale rather than silently wrong.
|
||||
dom = re.search(r"(\d+) field\(s\) observed: (\d+) vary, (\d+) constant",
|
||||
read(os.path.join(RE_ROOT, "findings/subsystems/value-domain-census.md")))
|
||||
if dom:
|
||||
tot, vary, const = (int(g) for g in dom.groups())
|
||||
L.append(f"- Value domains: **{vary}/{tot}** typed fields have been seen to vary "
|
||||
f"{bar(vary, tot)} — the other **{const}** have only ever held one value "
|
||||
f"across the corpus, so their typing is untested (`value-domain-census.md`)")
|
||||
else:
|
||||
L.append("- Value domains: ? (findings/subsystems/value-domain-census.md unparsed)")
|
||||
L.append("")
|
||||
|
||||
# 5 engine
|
||||
mods = engine_modules(engine)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue