mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-26 13:33:34 -04:00
00812fc62f
THE DOC GAP, and it cost tokens this session. `docs/automation-runbook.md` was titled "the
autonomous campaign, as it actually runs" while documenting the RETIRED OpenRouter/ox-alpha system
whose lanes are all deliberately DEAD. The current Claude-wave pipeline existed only as two dense
tooling-inventory rows in SETUP.md — reference, not procedure. Three of this session's costliest
mistakes were procedural and a playbook prevents each:
* hand-typed a refill target -> invented func_80184F60 (2nd instruction of a matched function), 58k
* hand-rolled a serial gate loop when parallel_gate existed -> ~1h for what took 103s
* re-derived a function banked verbatim in ~20 overlays -> 102k
NEW docs/wave-playbook.md — start to finish, each guard paired with the MEASUREMENT that produced it
(that pairing is the part a generic decomp guide cannot have, and the seed of the future template).
automation-runbook.md retitled HISTORICAL with a pointer; SETUP.md §6.9 links the playbook.
NEW tools/seed_ref.py — the cross-TU banked twin, joined on corpus signature hashes (no atlas knn,
~2s fleet-wide), wired into t5_cards.py. FLEET: 87 open stubs have a banked twin; 41 of them sit in
twin_sweep's refusal ledger, invisible to BOTH tools at once. Documents twin_sweep's two holes:
load_sigs covers 141/213 binaries (main, resident, all md_MAIN_* absent), and one curated symbol
name silently disables an entire binary via a bare `except Exception: pass`.
Schema note: seed_ref's binary/fn are the EXEMPLAR's, because api_agent greps src/{binary} for {fn};
naming them after the target would send every agent grepping for itself — caught pre-ship.
HARVEST §333-§338 from the s67o2_1/pool_1 waves:
§333 frame size is set by DECLARED aggregates, not used ones — an unreferenced trailing local is a
dial (3 instances; one worth 30 of 32 residual rows)
§334 a reload spill slot rounds to BIGGEST_ALIGNMENT for align AND size: one 4-byte pseudo grew a
frame by 16 (82->53)
§335 `extern u16 A[]` at a variable subscript allocates ~8B/access of dead stack temps that inflate
the frame with ZERO extra instructions — invisible in a body diff (141->20)
§336 the §5a barrier goes at the BOTTOM of the twin; find_cross_jump walks BACKWARD
§337 the CC1-ONLY blocker class: blocker_probe's static oracle says "none" and cc1 still fails
§338 _sltiu_bounds misreads a non-switch sltiu as a bounds check, over-spanning the table
gate_wave.py now STREAMS both lanes (R55) — it captured output and printed at the end, leaving a
zero-byte log indistinguishable from a hang.
71 lines
4.3 KiB
Python
71 lines
4.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
|
|
import seed_ref as SR
|
|
|
|
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, n_sr = [], 0, 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 = []
|
|
# seed_ref — THE CROSS-TU BANKED TWIN. Built from the signature hashes the corpus already
|
|
# computes (NOT the atlas knn, which is why this was skipped before). Measured cost of not
|
|
# having it: an opus agent spent 102,193 tokens re-deriving ov_SC03_107:func_8013DD68, whose
|
|
# body is banked verbatim at the same address in ov_MAIN_012 — because the card asserted
|
|
# "no banked twin". 87 open stubs fleet-wide have one; 41 of those sit in twin_sweep's
|
|
# refusal ledger, so they are invisible to BOTH tools at once.
|
|
try:
|
|
sr = SR.for_stub(t['binary'], t['name'])
|
|
except Exception as e:
|
|
print(' seed_ref failed for %s/%s: %s' % (t['binary'], t['name'], str(e)[:80])); sr = None
|
|
n_tu += bool(tu_ref); n_dp += bool(dp); n_sr += bool(sr)
|
|
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, 'seed_ref': sr})
|
|
p = a.out or os.path.join(a.wave, 'cards.json')
|
|
json.dump(cards, open(p, 'w'), indent=1)
|
|
n_ref = sum(1 for c in cards if (c.get('seed_ref') or {}).get('mechanical_remap_refused'))
|
|
print('cards: %d built for %s (tu_ref %d/%d = %.0f%%; decl_prior %d/%d = %.0f%%; '
|
|
'seed_ref %d/%d = %.0f%%, of which %d were mechanically refused — copy the BODY, expect a '
|
|
'declaration blocker)'
|
|
% (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)),
|
|
n_sr, len(targets), 100.0 * n_sr / max(1, len(targets)), n_ref))
|
|
print('wrote %s' % p)
|
|
if __name__ == '__main__':
|
|
main()
|