#60 PART 2: the RE-EXPORT -- dark code 90KB -> 41KB, coverage 87.3% -> 93.5%

Installed JDK 21 + Ghidra 12.1.2 (no admin, %LOCALAPPDATA%\bt411-tools beside
DXSDK/cmake; runner uses 8.3 SHORT paths because Ghidra's .bat expands
%JAVA_HOME% unquoted and the profile has a space).

New tooling: reference/ghidra_scripts/ExportGaps.java -- ExportAll's exact
output contract PLUS a gap-fill pass (force disassembly + createFunction at
E8 call targets outside functions, data->code pointers at a plausible
prologue, and the census's discovered starts; iterated to a fixpoint,
logged to gapfill_report.tsv).  tools/ghidra_reexport.sh (headless runner,
'reprocess' mode) and tools/gapdiff.py (score two censused exports);
gapcensus.py now censuses any export dir.

Results: 6267 -> 6472 functions (+205 created in 2 rounds: 195 census
starts, 6 call targets, 4 data pointers; 56.1KB newly covered), ZERO
decompile failures.  Dark real code 90.4 -> 40.8 KB (54.8% recovered);
game-side dark 53.1 -> 21.1 KB; regions 428 -> 321.  EVERY historically
dark function now has pseudocode -- including @0x4c05c4 VehicleDead, the
absence that opened this issue.

VALIDATION: the new pseudocode confirms this week's hand reconstruction of
the crouch field-for-field (mapPosture/duckState/squatCapable/myomerEff/
novice gate/SetLegAnimation/ForceUpdate/stability alarm) -- and exposed one
branch the raw pass missed: AIRBORNE AUTO-RISE (mode 3|4 && legState 1 ->
forced squ), now implemented in mech4.cpp and re-benched un-regressed.

PROMOTION: the re-export is canonical reference/decomp/; the previous export
is preserved at reference/decomp/archive_2025export/ so old
`part_0NN.c:LINE` citations still resolve (addresses are stable across both;
line/shard membership is NOT -- cite @ADDR).

New lead recorded: @0x4c0904 is the MASTER BTPlayer Performance (team
resolution, EndMission console post, score heartbeat) -- our @0x4c083c
PlayerSimulation attribution needs a re-check.  KB: source-completeness,
gotcha #20 (the rule is cheap now -- look it up), CLAUDE.md router/layout.
Log: phases/phase-04-gap-census.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Joe DiPrima
2026-08-06 11:11:26 -05:00
co-authored by Claude Fable 5
parent e69c0d7aa8
commit f44be87ab2
52 changed files with 239808 additions and 39954 deletions
+5 -1
View File
@@ -571,7 +571,11 @@ produced four wrong conclusions, two of them [T1]-tagged at the time:
- for content claims, walk the **BTL4.RES TOC** (`tools/resscan.py` pattern), not the loose tree;
- check `reference/BT410_SOURCE_MANIFEST.md` + `game/reconstructed/CLASSMAP.md`;
- and tag the claim's tier by the WEAKEST source consulted — an export-only sweep caps at [T4].
The #60 gap census (dark-region inventory + a fresh Ghidra re-export) is the systemic fix.
The #60 gap census + RE-EXPORT is the systemic fix, and BOTH shipped 2026-08-06: the export
now covers 93.5% of .text (dark code 90 KB → 41 KB) and `reference/decomp/GAP_CENSUS.md` maps
what is still dark. **So the rule is cheap now: look the address up in GAP_CENSUS.md first.**
If it is NOT in a dark region, the export is authoritative and "absent" means absent. If it IS,
byte-scan before claiming anything. (Toolchain + method: `phases/phase-04-gap-census.md`.)
## Key Relationships
- Applies to: every topic that reconstructs a class ([[subsystems]], [[combat-damage]], [[gauges-hud]], [[locomotion]]).
+20 -7
View File
@@ -94,18 +94,31 @@ its recorded line 400 exactly. [T1/T3 per the sidecar]
Plus `BTL4OPT.EXE` as a behavioral **oracle** (run under cdb / read the decomp). Result =
behavior-equivalent **reconstruction**, NOT original source. [T2]
## THE GAP CENSUS (2026-08-06, #60) — the dark-region inventory [T1]
## THE GAP CENSUS + RE-EXPORT (2026-08-06, #60) — BOTH HALVES DONE [T1]
**The export was REBUILT 2026-08-06** (Ghidra 12.1.2 headless + `ExportGaps.java`'s gap-fill
pass): index coverage **87.3% → 93.5%**, dark real code **90.4 KB → 40.8 KB (54.8% recovered)**,
game-side dark 53.1 → 21.1 KB, functions 6,267 → **6,472** (+205, zero decompile failures).
Every historically-bitten dark function now has pseudocode — including `@0x4c05c4` VehicleDead,
the absence that opened #60. The re-export CONFIRMED the crouch reconstruction field-for-field
and revealed one branch the raw pass missed (airborne auto-rise, fixed same day).
**The old export is archived at `reference/decomp/archive_2025export/`** — addresses are
stable across both, but `part_0NN.c:LINE` citations only resolve against the archive. Cite
`@ADDR`, not part/line. Pipeline: `tools/ghidra_reexport.sh``tools/gapcensus.py`
`tools/gapdiff.py`. Toolchain (JDK 21 + Ghidra 12.1.2) lives in `%LOCALAPPDATA%\bt411-tools`;
the runner MUST use 8.3 short paths (Ghidra's .bat expands %JAVA_HOME% unquoted and the user
profile has a space). Full log: `phases/phase-04-gap-census.md`.
### The original inventory (part 1, same day) [T1]
`tools/gapcensus.py``reference/decomp/GAP_CENSUS.md` + `gap_census.tsv` (regenerate after
any re-export). Headline: .text 892 KB; the index covers 87.3%; **428 dark regions = 90 KB of
real code Ghidra never made into functions** (indexed-but-unexported = 0 — the gap class is
purely "not indexed"). Game-side (bt/ + bt_l4/ + boundary) dark ≈ 54 KB: 66 regions already
visited by past digs, **159 never touched**. Validation: all six historically-bitten dark
any re-export; it censuses whatever dir you point it at). As found BEFORE the re-export: .text
892 KB, index 87.3%, **428 dark regions = 90 KB of real code** (indexed-but-unexported = 0 —
the gap class is purely "not indexed"), game-side dark ≈ 54 KB with 159 regions never touched.
Current numbers are in the header above. Validation: all six historically-bitten dark
addresses (VehicleDead, ToggleLamp, death tail, master-perf, myomer integrator, duck consumer)
land inside census regions. Top uncharted leads + method: `phases/phase-04-gap-census.md`.
**RULE (gotcha §20):** consult the census BEFORE any "absent from the export/binary" claim —
if the address falls in a dark region, the claim needs byte-scan evidence, not export silence.
Second half still open: a Ghidra re-export (scripts ready in `reference/ghidra_scripts/`; no
local install) forcing disassembly at the 332 discovered starts would convert most of it.
(The second half — the re-export — landed the same day; see the header.)
## Key Relationships
- Feeds: [[reconstruction-method]] (the loop that fills the gap), [[decomp-reference]].