3.3 KiB
§33 — Automating the giant decl-reconcile: tools/reconcile_decls.py (the DATA analog of §20's cast_call_sites) + a fleet-majority type oracle (Phase 24 T7b, byte-proven on func_80129CF8)
The gap. A freshly-matched giant/wave draft byte-matches STANDALONE with its own guessed decls, but to bank ×1 (and then propagate ×134 via a shared DEFINE_func_* macro that EMBEDS its externs) its callee/data externs must be FLEET-CANONICAL, else conflicting types in-TU. cast_call_sites (§20) does this for callee FUNCTIONS; reconcile_decls does it for DATA symbols D_XXXX — the class the giants hit (they hoist global base ARRAYS, §32). It was the last manual step in the giant pipeline.
The oracle (fleet-majority type picker) — new; none existed (gen_harvest_targets read only engine_core.h + ONE overlay, first-seen-wins, never saw a fleet disagreement). reconcile_decls.canonical_data_map(): an engine_core.h macro decl is AUTHORITATIVE (the shared/propagated set every overlay co-instantiates — conform to it and the macro can't conflict per-overlay); else the plurality across ALL overlays + resident.c (tie → lexicographically-first spelling, deterministic). Verified 8/8 on func_80129CF8's symbols (--print-canon D_XXXX inspects one).
Byte-neutral cast taxonomy (the DRAFT's decl type = the intended access; cast every use to reproduce it under the CANONICAL storage decl → gcc folds the compile-time cast → identical opcode; the whole-binary byte-gate is the sole arbiter, fail-closed):
| draft decl | canonical | decl → | access → |
|---|---|---|---|
array Ed[] |
array Ec[] (Ed≠Ec) |
Ec[] |
D_x → (Ed*)D_x; D_x[i] → ((Ed*)D_x)[i] |
array Ed[] |
struct / scalar | canon | D_x → (Ed*)&D_x (address-of the object) |
scalar Td |
scalar Tc (signed/width) |
Tc |
D_x → *(Td*)&D_x (forces the Td opcode, e.g. lbu under s8) |
ptr P* D_x |
scalar Tc |
Tc |
D_x → (*(P **)&D_x) (cast-lvalue: store/read a pointer in the scalar slot) |
Implementation: ONE re.sub per symbol with a replacement fn (captures the optional leading & / following [), single-pass so a symbol in several forms on one line can't double-wrap (the first draft double-wrapped the ptr-store — the two-sub read+write templates re-matched; collapsed to one pass). |
Pipeline placement: canon_resident_calls → cast_call_sites → reconcile_decls → sig_unify → harvest_verify --chunk 1 (wired into gate_stage; idempotent / no-op on drafts without a data conflict → can't regress the wave). Standalone giant use: tools/reconcile_decls.py --overlay <ov> --src-file src/<ov>/<ov>_a.c --in <drafts> --out <drafts>-rc.
Byte-proof (T7b, no Fable5 needed): the full loose func_80129CF8 (intended decls s32 D_80126948[] … , un-cast accesses) → reconcile_decls (5 symbols reconciled) → swapped into the DEFINE_ macro → make build BINARY=ov_SC01_077 = BYTE-IDENTICAL d19c9580.
R14 — the tool is an AUTOMATION, not an "unlock": func_80129CF8 banks ×134 FREE via existing dedup_propagate --recover once reconciled (the "×134 wall" was a stale-asm misdiagnosis, §32). reconcile_decls' value is removing the manual ×1-reconcile step for every future giant / loose draft (the 6 sibling giants + the wave tail), not unblocking propagation.