dashboard: count addresses.d fragments (was undercounting 615 vs 722), read layouts.json (22 -> 384), fix the layouts denominator and the 'objects' type row

This commit is contained in:
alex 2026-09-08 08:30:46 -04:00
parent e1f038e440
commit 648e9aae77
2 changed files with 34 additions and 21 deletions

View file

@ -1,6 +1,6 @@
# SotS RE campaign — coverage dashboard # SotS RE campaign — coverage dashboard
Generated 2026-09-08 12:29 UTC · `sots-re` @ 136f98b,2026-09-08 · `sots-engine` @ c883a32,2026-09-08 (106 commits) · regenerate with `tools/dashboard.py` Generated 2026-09-08 12:30 UTC · `sots-re` @ e1f038e,2026-09-08 · `sots-engine` @ c883a32,2026-09-08 (106 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
@ -18,20 +18,19 @@ Generated 2026-09-08 12:29 UTC · `sots-re` @ 136f98b,2026-09-08 · `sots-engine
| Type | verified | mapped | in-progress | backlog | blocked | total | | Type | verified | mapped | in-progress | backlog | blocked | total |
|---|---:|---:|---:|---:|---:|---:| |---|---:|---:|---:|---:|---:|---:|
| objects | 5 | 2 | 0 | 0 | 0 | 7 | | objects | 20 | 6 | 0 | 2 | 1 | 29 |
| control-flow | 2 | 2 | 0 | 1 | 0 | 5 | | control-flow | 2 | 2 | 0 | 1 | 0 | 5 |
| subsystems | 3 | 7 | 1 | 3 | 1 | 15 | | subsystems | 3 | 7 | 1 | 3 | 1 | 15 |
| engine | 16 | 0 | 0 | 0 | 0 | 16 | | engine | 16 | 0 | 0 | 0 | 0 | 16 |
| verify | 23 | 3 | 0 | 8 | 0 | 34 | | verify | 23 | 3 | 0 | 8 | 0 | 34 |
| phase2 | 10 | 3 | 1 | 2 | 0 | 16 | | phase2 | 10 | 3 | 1 | 2 | 0 | 16 |
| meta | 19 | 4 | 0 | 1 | 0 | 24 | | meta | 19 | 4 | 0 | 1 | 0 | 24 |
| other | 15 | 4 | 0 | 2 | 1 | 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: **22** / 179 serializable types `[█░░░░░░░░░] 12%` — heuristic: distinct `Game::X`/`Mars::X` in `##`–`####` headings of `struct-recovery.md` + `schema-gaps-resolved.md` - 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): **615**, verified **607** `[██████████] 99%` - Functions: **41,411** (parsed from `01-fingerprint.md`); named/annotated in the **address contract** (`ghidra/addresses.json`, not Ghidra's full rename count): **723**, verified **703** `[██████████] 97%`
## 3. Data layer ## 3. Data layer
@ -96,10 +95,10 @@ Most recent open:
## 8. Delta since previous dashboard ## 8. Delta since previous dashboard
- verified targets: 92 → 93 (+1) · mapped-or-better: 117 → 118 (+1) - verified targets: 93 → 93 (+0) · mapped-or-better: 118 → 118 (+0)
- engine LOC: 35,208 → 35,208 (+0) · test files: 94 → 94 (+0) · checks: 3,142 → 3,142 (+0) - engine LOC: 35,208 → 35,208 (+0) · test files: 94 → 94 (+0) · checks: 3,142 → 3,142 (+0)
- addresses verified: 607 → 607 (+0) · recovered layouts: 22 → 22 (+0) · open questions: 26 → 26 (+0) - addresses verified: 702 → 703 (+1) · recovered layouts: 384 → 384 (+0) · open questions: 26 → 26 (+0)
--- ---
warnings: board.md: unknown types objects; 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: 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": 93, "mapped_plus": 118, "targets": 139, "loc": 35208, "tests": 94, "checks": 3142, "addr_verified": 607, "addr_total": 615, "layouts": 22, "open_q": 26} --> <!-- dashboard-metrics {"verified": 93, "mapped_plus": 118, "targets": 139, "loc": 35208, "tests": 94, "checks": 3142, "addr_verified": 703, "addr_total": 723, "layouts": 384, "open_q": 26} -->

View file

@ -11,6 +11,7 @@ Parsing is tolerant: malformed inputs are reported in the footer "warnings" line
""" """
import argparse import argparse
import datetime import datetime
import glob
import json import json
import os import os
import re import re
@ -22,7 +23,7 @@ WARN = []
FUNCTIONS_FALLBACK = 41411 # findings/01-fingerprint.md, in case the number cannot be parsed FUNCTIONS_FALLBACK = 41411 # findings/01-fingerprint.md, in case the number cannot be parsed
STATUSES = ["verified", "mapped", "in-progress", "backlog", "blocked"] STATUSES = ["verified", "mapped", "in-progress", "backlog", "blocked"]
TYPE_ROWS = [ # (label, board Type values) TYPE_ROWS = [ # (label, board Type values)
("objects", ("object",)), ("control-flow", ("control-flow",)), ("subsystems", ("subsystem",)), ("objects", ("object", "objects")), ("control-flow", ("control-flow",)), ("subsystems", ("subsystem",)),
("engine", ("engine",)), ("verify", ("verify",)), ("phase2", ("phase2",)), ("meta", ("meta",)), ("engine", ("engine",)), ("verify", ("verify",)), ("phase2", ("phase2",)), ("meta", ("meta",)),
] ]
@ -102,9 +103,17 @@ def parse_functions(path):
def recovered_layouts(paths): def recovered_layouts(paths):
"""Heuristic: unique `Game::X` / `Mars::X` names appearing in ##/###/#### headings of the """Classes with a recovered member layout.
struct-recovery docs, excluding purely descriptive headings (no backticked class)."""
Primary source is objects/layouts.json (the serializer-recovery output — machine-generated,
hundreds of classes). The heading heuristic over the hand-written struct-recovery docs is kept
as a supplement: it catches classes recovered by hand that the serializer pass never saw."""
names = set() names = set()
try:
d = json.loads(read(rp("objects", "layouts.json")) or "{}")
names.update(k for k in d if "::" in k)
except json.JSONDecodeError as e:
warn(f"layouts.json: {e}")
for p in paths: for p in paths:
for ln in read(p).splitlines(): for ln in read(p).splitlines():
if re.match(r"^#{2,4} ", ln): if re.match(r"^#{2,4} ", ln):
@ -114,12 +123,16 @@ def recovered_layouts(paths):
def parse_addresses(path): def parse_addresses(path):
try: # addresses.json plus every per-lane ghidra/addresses.d/*.json fragment — the same set
d = json.loads(read(path) or "{}") # gen_addresses.py merges. Counting only the base file undercounts while lanes are in flight.
entries = d.get("entries", d if isinstance(d, list) else []) sources = [path] + sorted(glob.glob(os.path.join(os.path.dirname(path), "addresses.d", "*.json")))
except json.JSONDecodeError as e:
warn(f"addresses.json: {e}")
entries = [] entries = []
for src in sources:
try:
d = json.loads(read(src) or "{}")
entries += d.get("entries", d if isinstance(d, list) else [])
except json.JSONDecodeError as e:
warn(f"{os.path.basename(src)}: {e}")
total = len(entries) total = len(entries)
verified = sum(1 for e in entries if str(e.get("status", "")).startswith("verified")) verified = sum(1 for e in entries if str(e.get("status", "")).startswith("verified"))
return total, verified return total, verified
@ -375,9 +388,10 @@ def render(engine, prev):
a_total, a_ver = parse_addresses(rp("ghidra", "addresses.json")) a_total, a_ver = parse_addresses(rp("ghidra", "addresses.json"))
L += ["## 2. Binary understanding", "", L += ["## 2. Binary understanding", "",
f"- RTTI type descriptors: **{n(rtti)}** (`Game::` {n(cg)}, `Mars::` {n(cm)}; serializable types {n(ser)})", f"- RTTI type descriptors: **{n(rtti)}** (`Game::` {n(cg)}, `Mars::` {n(cm)}; serializable types {n(ser)})",
f"- Classes with recovered member layouts: **{len(layouts)}** / {ser} serializable types " f"- Classes with recovered member layouts: **{len(layouts)}** / {n(cg + cm)} named classes "
f"{bar(len(layouts), ser)} — heuristic: distinct `Game::X`/`Mars::X` in `##`–`####` headings of " f"{bar(len(layouts), cg + cm)} — `objects/layouts.json` (serializer recovery) plus classes "
f"`struct-recovery.md` + `schema-gaps-resolved.md`", f"recovered by hand in `struct-recovery.md` + `schema-gaps-resolved.md`. Note {ser} types are "
f"*serializable*; the recovery also reaches non-serializable ones, so this is not a subset of that",
f"- Functions: **{n(funcs)}** ({fsrc} from `01-fingerprint.md`); named/annotated in the **address contract** " f"- Functions: **{n(funcs)}** ({fsrc} from `01-fingerprint.md`); named/annotated in the **address contract** "
f"(`ghidra/addresses.json`, not Ghidra's full rename count): **{a_total}**, verified **{a_ver}** " f"(`ghidra/addresses.json`, not Ghidra's full rename count): **{a_total}**, verified **{a_ver}** "
f"{bar(a_ver, a_total)}", ""] f"{bar(a_ver, a_total)}", ""]