Audit of what actually landed in context/ versus what only ever got said in
chat. Five gaps and one stale claim repeated in four files.
New env gates were the biggest hole -- BT_TORSO_LOG, BT_MYOMERS_LOG,
BT_MYOMERS_REPAIR_TEST, BT_SELF_DAMAGE and BT_POWER_DETACH_TEST were all in the
code and none of them in decomp-reference §6, which is supposed to be the hub.
Added with the reasoning that makes them usable: why the myomers probe samples
every frame while unpowered (the NoVoltage window is about a second and a 1 Hz
probe steps straight over it), why the repair test also forces Manual (or
AutoConnect restores power a frame later), why SELF_DAMAGE latches off at the
first death, and why DETACH_TEST taking a NAME is what proves failover rather
than a same-generator re-attach.
The 6am log day was in the code and the player bats but not the KB. Now in
build-and-run with the stem table, the unconditional append, the 8 MB part
roll-over and the BT_LOG-truncates trap, plus the operator-facing note in
operator-console and OPERATOR_GUIDE that you ask for the NEWEST log, never
"today's".
Recorded the crash-symbolization gap, which is the one with teeth. BTCrashFilter
writes a stack into the day log and its own comment claims "we hold the PDB". We
do not: no Release PDB is produced at all, and /O2 implies /Oy so the EBP walk is
unreliable anyway. When the Owens crash finally lands we get an address we cannot
resolve. Written down with the fix (/Oy-, /Zi + /DEBUG, archive the PDB per
build) rather than left as something I mentioned once.
New gotcha 22: HeatModelOff() reads simulationState == 1, i.e. "am I destroyed",
and has nothing to do with the heat model. Behaviour at the call sites is right,
the name is not, and while chasing #70 it reads as "novice pilots cannot twist"
and sends you hunting an experience-level bug that does not exist. Same misnomer
in torso/gyro/sensor headers.
Also documented the dist flavor trap, having nearly shipped it myself: mkdist
reads build/CMakeCache.txt, so a tree configured BT_STEAM=OFF silently produces
a -nosteam zip with no play_steam.bat and no steam_api.dll. OFF is the CMake
default; ON is the documented dev state.
Swept the stale `btl4.log` filename out of reconstruction-gotchas,
reconstruction-method, build-and-run and CLAUDE.md itself -- the log has been
<stem>_YYYYMMDD.log since 1777d5a and every "read btl4.log" instruction was
pointing at a file that is no longer written.
checkctx CLEAN.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3.9 KiB
id, title, status, source_sections, related_topics, key_terms
| id | title | status | source_sections | related_topics | key_terms | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| reconstruction-method | Reconstruction Method — the loop, the no-stand-ins rule, decomp technique | established | PROGRESS_LOG.md §10b, §5a (decompilation), §10c |
|
|
Reconstruction Method
How the missing BT game logic is rebuilt from the binary. The governing rule: no stand-ins.
Full detail: docs/PROGRESS_LOG.md §10b; the systemic bug classes are reconstruction-gotchas.
The loop (per feature)
- Read the RAW decomp
reference/decomp/all/part_*.cfor the relevantFUN_xxxx. - Map
FUN_/DAT_/this+0xNNto engine symbols using: the BT headers + the WinTesla MUNGA source +game/reconstructed/CLASSMAP.md+ RP's parallel code (VTV≈mech, WEAPSYS≈weapons). - Write the real reconstruction into
game/reconstructed/*.cpp. - Build; run env-gated; read
content\<stem>_YYYYMMDD.log(grep[anim]/[drive]/[target]/[fire]/[damage]markers). - cdb on any crash.
static_assert-lock the layout against the binary's offsets. [T2]
RULE: no stand-ins
The full game logic IS in the pseudocode (the binary ran the game); a "gap" is a reconstruction
stub not yet filled, not a hole in the original. Never write stand-in/placeholder logic for an
apparent gap — read the decomp. (User: "there are no gaps, just work to be done.") Bring-up
scaffolding (the BT_AUTOFIRE/BT_AUTODRIVE/BT_GOTO env harness; historically
explosion-for-beam and a player-gated drive, since replaced by the real reconstructions) is
clearly MARKED and meant to be REPLACED by the real reconstructed system, never to substitute
for reading the decomp. [T2]
Decompilation stack (established)
- Ghidra 12.1.2 + JDK21 are an EXTERNAL install (
tools/holds only python utilities); the headless scripts live inreference/ghidra_scripts/(ExportBTSource.java,DecompVSS.java,ExportAll.java).ExportBTSource.javarun headless onBTL4OPT.EXE→ decompiled C inreference/decomp/(bt_<src>.cpp.cassert-anchored files; bulk pseudocode inreference/decomp/all/part_*.c). The pass is assert-anchored (few funcs/file — anchored on the asserts that carry source paths). [T2] - For a
FUN_the assert-anchored exporter skipped:tools/disas2.py <VA> [len](capstone disassembly ofBTL4OPT.EXE— recovers x87 math Ghidra drops, folds known calls + float constants). OrDecompVSS.java(headless address-list decompiler). [T2] - Resolving a
.datafn-pointer (aPTR_LAB_xxxxcallback/vtable slot the decomp didn't export): PE-parse the DWORD at its VA, then capstone-disassemble the target. Used for the gait callbacks (@0x4a6d8c), the valve handler (@0x4ae464), gauge widget slots. [T2] .datafloat constants are the biggest "couldn't recover" bucket (tuning values); read them as the x87 80-bitfloat10the decomp uses, not 32-bit float (scratchpad/rdtbyte.py). [T2]
Effort model (honest)
~0.5-1.5 hr/module → ~30-50 agent-hours + human review for ~40 modules, with a long tail (modules
with no surviving .HPP fragment, or split across decomp windows, cost more). Process upgrades:
per-class function lists (not address clusters), complete vtable rows, recover .data constants. [T3]
Workflows (for scale)
For exhaustive multi-function decomp analysis, fan out a read-only Workflow (understanding phase — one agent per function/class produces an offset map + findings, + an adversarial verify), THEN implement hands-on so each change is visible + consistent. This is the §10c pattern; used for the ground-model decode (10 agents), the alarm-unification (8), the gauge-widget decode (6). [T2]
Key Relationships
- Bug classes: reconstruction-gotchas (check FIRST). Reference data: decomp-reference.
- Why it's needed: source-completeness.