Files
BFM-decomp/tools/warmstart.py
T
Drew T 6cd81173cd feat(phase-31 T9): warmstart feeder + weak-cards — the campaign lanes are armed
- tools/warmstart.py: --from-banked walks a banked exemplar's family's open
  members, builds remapped proven-body drafts (symbol_map + build_draft), and
  STREAM-classifies member-vs-seed with zero compiles; enqueues ONLY permuter-
  shaped work (bucket==permuter or LENGTH-DRIFT |delta|<=2) as backlog records;
  --lenmiss ingests T8's 49-route. Armed live: 59 enqueued, 120 refused by the
  stream filter (the anti-92%-wasted-CPU discipline)
- grinder patch NOT needed: candidates() deliberately keeps unclassified
  records ('unknown is not a reason to skip'), so pre-filtered enqueues flow
  as-is — documented in the feeder docstring (YAGNI honored)
- family_cousins --weak-cards: 954 seeded-crack cards from the never-consumed
  0.70-0.85 band, ins-ranked, §168 laws embedded, model-routed haiku 804 /
  v3 43 / sonnet 86 / opus 21 (cheap tiers dominate), 0 unresolved .s
2026-08-14 19:59:21 -06:00

168 lines
6.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""P31 T9 — the permuter/grinder FEEDER: warm-start drafts from banked exemplars + routed fuel.
WHY: the grinder's own audit (Phase-22) showed 92% of its CPU went where the permuter provably
cannot win; its targeting fix admits autopsy `bucket=="permuter"` and — deliberately — KEEPS
unclassified records ("unknown is not a reason to skip", R32). So a feeder that enqueues ONLY
pre-verified permuter-shaped work needs NO grinder patch: it appends backlog near-records
(source=warmstart) whose drafts are remapped PROVEN sibling bodies, and the daemon picks them up.
Modes:
--from-banked fn[,fn…] --binary B for each newly-banked exemplar: walk its h_seq family's
still-open members (the atlas group's mechanical remainder); for each, build the remapped
seed draft (family_remap.symbol_map — refuses on reloc-count mismatch) and STREAM-CLASSIFY
member-vs-seed with ZERO compiles (both are ground-truth bytes); enqueue only
bucket==permuter or LENGTH-DRIFT |Δ|<=2.
--lenmiss ingest .run/lenmiss/permuter.json (T8's |Δ|<=2 clean-drift route, drafts already
on disk) as warmstart backlog records.
The whole-binary byte-gate remains the arbiter; a wrong enqueue costs grinder CPU, never a byte.
"""
import argparse, json, os, sys
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import backlog
import corpus
import family_remap as FR
import family_cousins as FC
import aprop_autodraft as APD
import residual_class
import sig_image
def stream_dicts(words, vram=0x80100000):
"""words -> masked_diff-shaped [{word, mnem, reloc_kind, reloc_op}] for classify_streams
(zero compiles: both sides are ground-truth bytes)."""
rel = FR.reloc_indices(words)
out = []
pending_hi = set()
for k, w in enumerate(words):
ins = sig_image.make_insn(w, vram + 4 * k)
mnem = ins.getOpcodeName().lower() if ins.isValid() else "?"
kind = None
if k in rel:
op = w >> 26
if op in (2, 3):
kind = "R_MIPS_26"
elif op == 0x0F:
kind = "R_MIPS_HI16"
pending_hi.add((w >> 16) & 31)
else:
kind = "R_MIPS_LO16"
out.append({"word": w, "mnem": mnem, "reloc_kind": kind, "reloc_op": None})
return out
def classify_pair(seed_words, member_words):
"""-> verdict dict from residual_class over the two byte-truth streams."""
return residual_class.classify_streams(stream_dicts(seed_words), stream_dicts(member_words))
def enqueue(rec, dry):
if dry:
print(" would enqueue:", rec["binary"], rec["name"], rec.get("klass"))
return
backlog.append_record(rec)
def from_banked(fns, binary, outdir, dry):
fam = json.load(open(".run/family_hseq.json"))["families"]
by_hs = {}
sig = corpus.sig(binary)
n_enq = n_ref = 0
for fn in fns:
addr = int(fn.split("_")[1], 16)
row = sig.get(addr)
if row is None:
print(f" {fn}: not in {binary}'s sig — skipped")
continue
hs = row["h_seq"]
f = next((x for x in fam if x["h_seq"] == hs), None)
if f is None:
print(f" {fn}: no family for its h_seq — ×1 bank, nothing to seed")
continue
seed_words = FR.stream_words(binary, addr, row["nins"])
body_ref = FC.seed_body_ref(binary, addr)
if not body_ref or body_ref.get("kind") == "unresolved":
print(f" {fn}: seed body unresolved — skipped")
continue
body, seed_text, _kind = APD.seed_body(body_ref, fn)
if body is None:
print(f" {fn}: seed body unreadable — skipped")
continue
for m in f["members"]:
mb, ma = m[0], (m[1] if isinstance(m[1], int) else int(str(m[1]), 16))
if mb == binary and ma == addr:
continue
st = corpus.stubs(mb)
if ma not in st:
continue # already banked
member_words = FR.stream_words(mb, ma, f["nins"])
if member_words is None:
continue
v = classify_pair(seed_words, member_words)
klass = v.get("klass")
delta = len(member_words) - len(seed_words)
ok = (v.get("bucket") == "permuter") or (klass == "LENGTH-DRIFT" and abs(delta) <= 2)
if not ok:
n_ref += 1
continue
mfn = st[ma].symbol
try:
renames, sm_err = FR.symbol_map(addr, binary, mb, to_addr=ma)
except Exception as e:
renames, sm_err = None, repr(e)[:60]
if renames is None:
print(f" {mfn}: symbol_map refused ({sm_err})")
n_ref += 1
continue
draft, skip = APD.build_draft(body, fn, mfn, renames, seed_text, "")
if draft is None:
print(f" {mfn}: build_draft skipped ({skip})")
n_ref += 1
continue
os.makedirs(f"{outdir}/{mb}", exist_ok=True)
p = f"{outdir}/{mb}/{mfn}.c"
open(p, "w").write(draft)
enqueue({"name": mfn, "binary": mb, "status": "near", "source": "warmstart",
"klass": v.get("profile") or klass, "closeness": v.get("closeness"),
"best_draft": p, "where_stuck": f"warmstart from {binary}:{fn}"}, dry)
n_enq += 1
print(f"warmstart --from-banked: enqueued {n_enq}, refused {n_ref}")
def from_lenmiss(dry):
rows = json.load(open(".run/lenmiss/permuter.json"))
n = 0
for r in rows:
enqueue({"name": r["fn"], "binary": r["binary"], "status": "near",
"source": "warmstart", "klass": "LENGTH-DRIFT",
"closeness": abs(r.get("delta") or 0),
"best_draft": r["draft"],
"where_stuck": "lenmiss permuter-length route"}, dry)
n += 1
print(f"warmstart --lenmiss: enqueued {n}")
def main():
ap = argparse.ArgumentParser(description=__doc__.split("\n")[0])
ap.add_argument("--from-banked", default=None, help="comma-separated banked fn names")
ap.add_argument("--binary", default=None)
ap.add_argument("--lenmiss", action="store_true")
ap.add_argument("--outdir", default=".run/warmstart")
ap.add_argument("--dry-run", action="store_true")
a = ap.parse_args()
if a.lenmiss:
from_lenmiss(a.dry_run)
if a.from_banked:
if not a.binary:
sys.exit("--from-banked needs --binary")
from_banked([x.strip() for x in a.from_banked.split(",") if x.strip()],
a.binary, a.outdir, a.dry_run)
if not a.lenmiss and not a.from_banked:
sys.exit("nothing to do: pass --lenmiss and/or --from-banked")
if __name__ == "__main__":
main()