Files
BFM-decomp/tools/t5_cards.py
T

57 lines
3.3 KiB
Python

#!/usr/bin/env python3
"""tools/t5_cards.py — BUILD the card fuel for a wave's own targets (P31 S63 T5).
Usage: t5_cards.py --wave .run/t5b [--out <wave>/cards.json]
WHY (byte-measured, P31 S63 wave t5a). `claude_wave_packs.py` looked cards up by BARE FUNCTION NAME
across `.run/wave_*_cards.json`; overlays share names at equal addresses, so 48 of 48 t5a targets
(and 15 of T4's 20) got ANOTHER binary's card — wrong banked twin, wrong TU neighbours, wrong
declarations. Nine agents independently reported discarding it. Keying by (binary, fn) fixes the
mis-attribution but leaves K-class ("never touched") targets with NO fuel at all, and `_fuel()`
then emits nothing: no `tu_ref`, no `decl_prior`. Yet t5a's agents cracked function after function
by finding an already-banked sibling in their own TU BY HAND ("in-TU twin ~150 lines earlier",
"structural twin in the SAME TU") — which is exactly what `tu_ref` is (§194-E, 62% of targets).
So this builds the two computable fields for the target ITSELF, from the same oracle
`build_wave_atlas` uses (`tools/wave_card_fuel.py`, R33):
tu_ref already-banked functions in the target's OWN TU, ranked by symbols shared with the
target's .s relocations
decl_prior the fleet's consensus signature for every symbol the .s references (§196) — kills
the two-arity A/B compile §195-A proved the asm cannot answer
`seed_ref` (the cross-TU banked twin) needs the atlas knn and is NOT built here: a card with no
seed_ref makes `_fuel` say "no banked twin — derive from the .s", which is TRUE, where the old
name-keyed card pointed confidently at an unrelated function. Coverage is printed (R32/R41)."""
import argparse, json, os, sys
REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__))); os.chdir(REPO)
sys.path.insert(0, 'tools')
import wave_card_fuel as F
import decl_prior as DP
def main():
ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
ap.add_argument('--wave', required=True)
ap.add_argument('--out', default='')
a = ap.parse_args()
targets = json.load(open(os.path.join(a.wave, 'targets.json')))
idx = DP.load()
cards, n_tu, n_dp = [], 0, 0
for t in targets:
tu = t.get('tu') or F.home_tu(t['binary'], t['name'])
tu_ref = F.tu_neighbours(t['binary'], t['name'], tu, t['asm'])
try:
dp = DP.for_asm(t['asm'], tu, idx=idx, binary=t['binary'])
except Exception as e:
print(' decl_prior failed for %s/%s: %s' % (t['binary'], t['name'], str(e)[:80])); dp = []
n_tu += bool(tu_ref); n_dp += bool(dp)
cards.append({'fn': t['name'], 'binary': t['binary'], 'addr': t.get('addr'), 'nins': t['nins'],
'sub': t['sub'], 'tu_ref': tu_ref, 'decl_prior': dp})
p = a.out or os.path.join(a.wave, 'cards.json')
json.dump(cards, open(p, 'w'), indent=1)
print('cards: %d built for %s (tu_ref on %d/%d = %.0f%%; decl_prior on %d/%d = %.0f%%; seed_ref not built — '
'the pack will honestly say "no banked twin")'
% (len(cards), a.wave, n_tu, len(targets), 100.0 * n_tu / max(1, len(targets)),
n_dp, len(targets), 100.0 * n_dp / max(1, len(targets))))
print('wrote %s' % p)
if __name__ == '__main__':
main()