mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-27 14:02:04 -04:00
ba6cb87d30
- tools/exemplar_miner.py: consume wall_taxonomy.json + per-overlay reach (dedup_propagate's computation) -> route each residual to a lever (WAVE/STRUCT/PINS/STUB); emit docs/exemplar_curriculum.md + .run/exemplar_routing.json (wave-gen input) - routing: WAVE 472 (218 reach-134, T6 fuel) / STRUCT 159 / PINS 114 (45 reach-134) / STUB 90 (74 ARITY_WALL loose-typing + 16 NONFAITHFUL, honest P9) - KEY T3 input: 17 reach-134 fns at m2c-mismatch=1 = cleanest regalloc/schedule isolates (likely SS17-pins wins + the genuine class residuals); 3 named exemplars confirmed reach-134 - note: census is the Jun-19 snapshot (pre-Phase-19 waves); T5/T6 regen = authoritative WAVE list
154 lines
8.4 KiB
Python
154 lines
8.4 KiB
Python
#!/usr/bin/env python3
|
||
"""exemplar_miner.py — route every residual stub to its lever, rank the reach-134 work (Phase 20 T2).
|
||
|
||
Consumes the residual census (tools/wall_taxonomy.json: per-stub bucket/nins/mismatch for the canonical
|
||
source overlay ov_SC01_077) and computes each stub's FLEET REACH (how many of the 134 overlays carry a
|
||
byte-identical copy, the ×N propagation leverage) the same way dedup_propagate does (h_exact over the
|
||
per-overlay sigs). It then:
|
||
- routes each bucket to a lever (WAVE / PINS / STRUCT / STUB) — ADVISORY; the byte-gate is the sole
|
||
arbiter (G3/P9), this is a worklist, not a correctness claim,
|
||
- emits the reach-134 WAVE-target list (T6 fuel; ranked reach desc, nins asc),
|
||
- surfaces the PINS/permuter-class reach-134 near-misses (the class-crack candidate pool for T3),
|
||
- tallies the honest STUB residual (ARITY_WALL loose-typing + NONFAITHFUL) and the STRUCT-context band.
|
||
|
||
Note: wall_taxonomy's `mismatch` is the M2C-DRAFT mismatch (scaffold quality), NOT the hand-match floor —
|
||
a STRUCTURAL_MISS with a high mismatch can still hand-match to a 1-instruction residual (e.g. the loop-guard
|
||
exemplar func_8012C2D0). So the buckets size the POOLS; the cleanest class-isolating exemplar is a Max pick.
|
||
|
||
Outputs: docs/exemplar_curriculum.md (human worklist) + .run/exemplar_routing.json (machine, for the wave gen).
|
||
Usage: tools/exemplar_miner.py [--source ov_SC01_077] [--census .run/wall_taxonomy.json] [--top 60]
|
||
"""
|
||
import argparse, json, os, sys, pathlib, datetime
|
||
|
||
ROOT = pathlib.Path(__file__).resolve().parent.parent
|
||
sys.path.insert(0, str(ROOT / "tools"))
|
||
import dedup_propagate as dp # load_sig, onboarded_overlays, registered_addrs (reach == its computation)
|
||
|
||
# bucket -> lever. ADVISORY routing (the byte-gate decides truth). Grouped by how we'd actually attack it:
|
||
# WAVE = m2c/hand-draftable by the Ultracode swarm + §17 toolkit + canon-first gate + fix_arity_callers
|
||
# STRUCT = m2c can't draft until a type is known (fn-ptr tables, jump tables, struct derefs)
|
||
# PINS = regalloc/schedule near-miss -> register-pins hand-match (permuter grind skipped this phase);
|
||
# the small-mismatch reach-134 ones are the class-crack candidate pool (T3)
|
||
# STUB = fundamental (loose-typing ARITY_WALL) or non-faithful (GTE/handwritten) -> honest INCLUDE_ASM
|
||
LEVER = {
|
||
"STRUCTURAL_MISS": "WAVE", "SIG_FIXABLE_KR": "WAVE", "LEAF_READY": "WAVE",
|
||
"MCOMPILE_arg-arity": "WAVE", "MCOMPILE_undeclared-other": "WAVE", "MCOMPILE_stack-var": "WAVE",
|
||
"MCOMPILE_m2c-incomplete-arg": "WAVE", "DATA_CONFLICT": "WAVE", "OTHER_CONFLICT": "WAVE",
|
||
"MCOMPILE_other": "WAVE", "VOID_VALUE_MISUSE": "WAVE",
|
||
"MCOMPILE_fnptr-call": "STRUCT", "M2C_DECOMP_FAIL": "STRUCT", "MCOMPILE_bad-deref": "STRUCT",
|
||
"MCOMPILE_bad-switch": "STRUCT",
|
||
"PERMUTER_CLASS": "PINS",
|
||
"ARITY_WALL": "STUB", "NONFAITHFUL_DEFER": "STUB", "NO_ASM": "STUB", "M2C_EMPTY": "STUB",
|
||
}
|
||
|
||
# the named class-crack exemplars carried from Phase 18/19 (T3 targets); the m2c bucket understates them.
|
||
CLASS_EXEMPLARS = {
|
||
"8012C2D0": "loop-guard operand-order (loop.c get_condition) — T3b",
|
||
"8014F2E0": "store-vs-load scheduling tie-break (sched.c) — T3c",
|
||
"8013C360": "-O0 %lo-folding cluster (address-mode split) — T3a",
|
||
}
|
||
|
||
|
||
def main():
|
||
ap = argparse.ArgumentParser()
|
||
ap.add_argument("--source", default="ov_SC01_077")
|
||
ap.add_argument("--census", default=".run/wall_taxonomy.json")
|
||
ap.add_argument("--top", type=int, default=60)
|
||
a = ap.parse_args()
|
||
|
||
recs = json.load(open(ROOT / a.census))
|
||
pool = dp.onboarded_overlays()
|
||
sigs = {ov: dp.load_sig(ov) for ov in pool}
|
||
reg = dp.registered_addrs()
|
||
|
||
def reach(addr_int):
|
||
h = sigs[a.source].get(addr_int, {}).get("h_exact")
|
||
if not h:
|
||
return 0
|
||
return sum(1 for ov in pool if sigs[ov].get(addr_int, {}).get("h_exact") == h)
|
||
|
||
rows = []
|
||
for r in recs:
|
||
ai = int(r["addr"], 16)
|
||
if ai in reg: # already matched+shared — not a residual
|
||
continue
|
||
lever = LEVER.get(r["bucket"], "WAVE")
|
||
rows.append({"addr": r["addr"].upper(), "nins": r["nins"], "mismatch": r.get("mismatch"),
|
||
"bucket": r["bucket"], "lever": lever, "reach": reach(ai)})
|
||
|
||
# machine output for the wave generator
|
||
os.makedirs(ROOT / ".run", exist_ok=True)
|
||
json.dump({x["addr"]: x for x in rows}, open(ROOT / ".run/exemplar_routing.json", "w"), indent=1)
|
||
|
||
# ---- human worklist ----
|
||
by_lever = {}
|
||
for x in rows:
|
||
by_lever.setdefault(x["lever"], []).append(x)
|
||
snap = datetime.datetime.fromtimestamp((ROOT / a.census).stat().st_mtime).strftime("%Y-%m-%d")
|
||
|
||
L = ["# BFM residual curriculum / router (generated by tools/exemplar_miner.py)",
|
||
f"# census: {a.census} (snapshot {snap}, {len(rows)} unregistered residual stubs in {a.source})",
|
||
"# reach = #overlays sharing the byte-identical copy (×N propagation leverage), computed from sigs.",
|
||
"# ROUTING IS ADVISORY — the per-overlay byte-gate is the sole arbiter (G3/P9). `mismatch` is the",
|
||
"# M2C-DRAFT mismatch (scaffold quality), NOT the hand-match floor.", "",
|
||
"## Routing summary (by lever, reach-weighted)", "",
|
||
"| lever | fns | reach-134 | Σ reach | what it is |", "|---|---|---|---|---|"]
|
||
desc = {"WAVE": "Ultracode swarm + §17 toolkit + canon-first gate (the yield engine, T6)",
|
||
"STRUCT": "m2c blocked on a type (fn-ptr/jump tables, struct deref) — needs type context",
|
||
"PINS": "regalloc/schedule near-miss — register-pin hand-match; class-crack pool (T3)",
|
||
"STUB": "fundamental loose-typing (ARITY_WALL) / non-faithful — honest INCLUDE_ASM (P9)"}
|
||
for lev in ["WAVE", "STRUCT", "PINS", "STUB"]:
|
||
g = by_lever.get(lev, [])
|
||
r134 = sum(1 for x in g if x["reach"] >= 134)
|
||
sreach = sum(x["reach"] for x in g)
|
||
L.append(f"| {lev} | {len(g)} | {r134} | {sreach} | {desc[lev]} |")
|
||
L.append("")
|
||
|
||
# WAVE pool, reach-134, ranked (T6 fuel)
|
||
wave134 = sorted([x for x in by_lever.get("WAVE", []) if x["reach"] >= 134],
|
||
key=lambda x: (-(x["reach"]), x["nins"] or 9999))
|
||
L += ["", f"## WAVE pool — reach-134, ranked (T6 fuel; {len(wave134)} fns, smallest first)", "",
|
||
"| addr | nins | bucket | reach |", "|---|---|---|---|"]
|
||
for x in wave134[:a.top]:
|
||
L.append(f"| {x['addr']} | {x['nins']} | {x['bucket']} | {x['reach']} |")
|
||
if len(wave134) > a.top:
|
||
L.append(f"| …+{len(wave134)-a.top} more | | | |")
|
||
|
||
# PINS / class-crack candidate pool, reach-134, smallest m2c-mismatch first
|
||
pins134 = sorted([x for x in by_lever.get("PINS", []) if x["reach"] >= 134],
|
||
key=lambda x: (x["mismatch"] if x["mismatch"] is not None else 999, x["nins"] or 9999))
|
||
L += ["", f"## PINS / permuter-class — reach-134 near-misses ({len(pins134)} fns; class-crack candidate pool)",
|
||
"", "| addr | nins | m2c-mismatch | reach |", "|---|---|---|---|"]
|
||
for x in pins134[:a.top]:
|
||
L.append(f"| {x['addr']} | {x['nins']} | {x['mismatch']} | {x['reach']} |")
|
||
if len(pins134) > a.top:
|
||
L.append(f"| …+{len(pins134)-a.top} more | | | |")
|
||
|
||
# the named T3 class exemplars + their census row + reach
|
||
rowmap = {x["addr"]: x for x in rows}
|
||
L += ["", "## Named class-crack exemplars (T3 — the Max spikes)", "",
|
||
"| addr | class | census bucket | nins | reach |", "|---|---|---|---|---|"]
|
||
for addr, note in CLASS_EXEMPLARS.items():
|
||
x = rowmap.get(addr)
|
||
if x:
|
||
L.append(f"| {addr} | {note} | {x['bucket']} | {x['nins']} | {x['reach']} |")
|
||
else:
|
||
L.append(f"| {addr} | {note} | (not a current stub — matched or split) | | |")
|
||
|
||
# STUB honesty tally
|
||
stub = by_lever.get("STUB", [])
|
||
from collections import Counter
|
||
sc = Counter(x["bucket"] for x in stub)
|
||
L += ["", "## STUB residual (honest, no lever — P9)", "",
|
||
f"{len(stub)} fns: " + ", ".join(f"{b}={n}" for b, n in sc.most_common()), ""]
|
||
|
||
open(ROOT / "docs/exemplar_curriculum.md", "w").write("\n".join(L) + "\n")
|
||
print(f"wrote docs/exemplar_curriculum.md + .run/exemplar_routing.json")
|
||
print(f" {len(rows)} residual stubs; WAVE {len(by_lever.get('WAVE',[]))} "
|
||
f"(reach-134 {len(wave134)}) | STRUCT {len(by_lever.get('STRUCT',[]))} | "
|
||
f"PINS {len(by_lever.get('PINS',[]))} (reach-134 {len(pins134)}) | STUB {len(stub)}")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|