Files
BFM-decomp/phase-ends/current/tasks/T3.md
T

6.0 KiB
Raw Blame History

T3 — head-type layouts and canonical files

Status: done | expert: expert-fable (2 attempts, handoff after c3) | ctx-at-completion: n/a | commit: see COMMIT | coder runs: c1 opus55 done (5aaa25154), c2 opus55 blocked→committed (e4341ee11), c3 opus55 done (1a35655ab) Done: the two head types and the player block are each defined once in include/struct_types.h (included by include/common.h, so visible to ov, main and md_* alike), every overlapping offset resolved by the max-site split with a per-offset record; proven IDENTICAL on 9 exemplar TUs across ov/md/main; restruct now sees include/ and no longer refuses nested-base overlap edits. Files:

  • include/struct_types.h — generated block (head_types.py) for Unkstruct_800B5CB8 (0x10C, 101 fields) and Unkstruct_80126B58 (0x24C, 152 fields); hand-written Unkstruct_80078E78 (0x98, evidence-named)
  • include/common.h:64 — #include "struct_types.h"
  • tools/head_types.py — new: max-site split over the struct map's layout ∪ conflicts (weighted-interval DP); --header, --decisions, --selftest
  • tools/type_census.py:56 — CANON_HEADERS = ("src/shared/engine_types.h", "include/struct_types.h")
  • docs/struct-map-decisions.md — canonical file set, resolution rule, player block, generated per-offset records
  • tools/delever.py — includers() follows -Iinclude (relative first, else include/x; scans include/*.h)
  • tools/restruct.py — pass_hint tolerates non-str residual rows; drop_overlaps keeps nested-base overlapping edits as KEPT(overlap-edit); +2 selftests (56)
  • src/800.c:8 — typedef Unkstruct_80078E78 Blk98_80029274; (byte-identical)
  • docs/struct-map.md, .run/P37/census/{struct_map_top.json,type_census.json,type_census.txt}, .run/P36/delever/calibration.json — regenerated outputs Decisions:
  • binding: head-type width conflicts resolve by the max-site split (the width most sites use wins the offset; the losers are recorded per offset in docs/struct-map-decisions.md); unions are deferred until a reader-facing reason appears (27 union candidates on 800B5CB8, 4 on 80126B58 listed there).
  • binding: the canonical file for cross-space types is include/struct_types.h reached through include/common.h, not per-space files — the map shows one layout per head across ov, md_* and main, so a per-space file would be a duplicate by construction.
  • Field names in the generated blocks stay unkHEX (G62); only the player block carries evidence-named fields (docs/actor-struct.md, memory-map §3.4). Deviations:
  • Unkstruct_80078E00 was defined as Unkstruct_80078E78: no cluster, global or access exists at 0x80078E00; the code's player record starts at 0x80078E78 (Blk98_80029274, Blk80078E78, D_80078E78 in 880 TUs) and its widths disagree with both heads. Same object, evidence-correct name; not a redefinition of the clause.
  • "one main exemplar" holds for 800B5CB8 (src/800.c) but not for 80126B58: the map has 0 main bodies for it (ov 16,773 · md 311 · main 0), so none can exist.
  • Plan's file list named src/shared/main/ and src/800_shared.h; the canonical file went to include/ instead (see Decisions), and three tool fixes outside the list were needed to prove the layouts (delever include graph; two restruct --try-file defects that pre-dated this task).
  • The verify of record ran after an extra prep step (R22 → snapshot-baseline → calibrate at 54c26d08a): the c3 commit had made the a1 calibration stale. Findings:
  • head_types: 800B5CB8 fields=101 kept_sites=75717 dropped_sites=25393 conflict_offsets=50 overlaps=167 misaligned=4 union_candidates=27; 80126B58 fields=152 kept_sites=61599 dropped_sites=1713 conflict_offsets=50 overlaps=71 misaligned=5 union_candidates=4.
  • 800B5CB8 drops 25 % of its sites in the split: it is a suspect merged cluster (several layouts keyed to one AT global); 80126B58 drops 1.5 %.
  • Exemplar proofs, all final IDENTICAL, 0 TYPE-NOT-VISIBLE: 800B5CB8 → ov_SC06_032_jr_80182890, ov_SC02_027_jr_8017D898, md_SC07_004, md_SC07_003, src/800.c; 80126B58 → ov_MAIN_012_jr_8015A3C8, ov_SC03_107_jr_8015A3C8, md_MAIN_046, md_MAIN_036 (.run/logs/t3c3_try_1..9.log).
  • REFUSED bodies in the exemplar runs were per-candidate compile errors (e.g. md_MAIN_036:300 ar46E98 undeclared), not layout faults.
  • The P37 T4e census had merged the heads as Unkstruct_800D3888 through a stale body_base_type.json; a fresh --sites census separates them. restruct reads .run/P37/census/* (hard-coded).
  • audit-types still 26 (all in engine_types.h, 0 in struct_types.h). Gotchas:
  • harness: restruct --selftest --real reads red after ANY commit (calibration pinned to a HEAD hash); the log/summary commit necessarily post-dates the verify. Re-prep = R22 → delever_oracle --snapshot-baseline → --calibrate ov_SC04_011 ov_SC03_015 md_SC07_004 main -j 16 (bare --calibrate refuses; ~4 min total).
  • harness: a /* 0xNN */ field comment nested inside another C comment kills the build; generated headers must not wrap offset comments.
  • generalizable: an include graph that ignores -I paths hides every type placed in include/ from the judge ("type not visible" on a visible type); model the compiler's search order (relative, then each -I dir).
  • harness: the expert's Bash hook denies reading tool sources even by range; use retriever-code. Research: none (three retriever-code answers, no reports) Next task needs: T4 applies include/struct_types.h fleet-wide via rung L cycles; Unkstruct_800B5CB8 is a split candidate for T5 (25 % dropped sites); 80126B58 has no main bodies; recalibrate before any --selftest --real; REFUSED bodies are compile errors to fix per candidate, not layout rejects. Verified: .venv/bin/python tools/restruct.py --selftest --real && make clean && make extract-all JOBS=16 && make check-all JOBS=16 → rc 0 at 54c26d08a after recalibration (calibrate 146/146 identical, positive control DIFFERS); restruct --selftest --real 61/61 OK; extract-all 217 extracted, 0 failed of 217; check-all 218 passed, 0 failed of 218 (.run/logs/t3_verify3.log) Full log: phase-ends/current/logs/T3.md