mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-27 22:45:39 -04:00
0840eda5bb
- match_one --emit-streams (additive; stdout-identity NC'd): word streams for the len lane - family_align.addr_true_rel: reloc-vs-constant range discriminator — FULL conservative set kept for pair semantics (NC-1 157/157 regression), address- true subset for indel eligibility only (a constant li-cluster must not read as reloc-in-indel); synthetic probes green both directions - tools/len_tells.py: aligned classification + §172b tell tagging (EXTPAIR/ SELECT/NOP) on target-side indels; detectors imported from atlas_features (R33); cookbook text embedded in cards - tools/lenmiss_route.py: pool-parallel (A8) — 587 audit LEN rows re-verified live + routed in 24s: redraft 345 (frac>0.35, APPEND-ONLY backlog reclassification — near-miss metrics stop lying) / permuter-length 49 (grinder fuel) / cards 192 incl 14 tell-tagged (the audit's own detectors had emitted ZERO) / mechanical 0 — an HONEST NULL: stored drafts rarely get constants wrong; LEN drift is shape, family_align's value here is classifier/detector - R32 accounting 587/587
85 lines
4.1 KiB
Python
85 lines
4.1 KiB
Python
#!/usr/bin/env python3
|
|
"""P31 T8 — classify a LEN±N near-miss (draft vs its OWN target) and build the routing card.
|
|
|
|
This is where `family_align` earns its keep (the T7 probe refuted the cousin use — but a draft vs
|
|
its own target is the SAME function, so registers agree outside the drift and the aligned
|
|
classifier's premise holds). Per draft:
|
|
|
|
- align draft↔target word streams (family_align.classify_aligned; draft = ex side, so the
|
|
mechanical repair swaps DRAFT literals toward the TARGET's)
|
|
- LEN-LI with resolvable clusters -> MECHANICAL repair candidate (swap the C literal, recompile)
|
|
- LEN-NOP / |Δ|<=2 clean drift -> permuter `length` profile
|
|
- LEN-STRUCT -> tag the target-side indels with the §172b tells
|
|
EXTPAIR target-extra sll/sra promotion pair (a multi-def s16/s8 the draft collapsed)
|
|
SELECT target-extra slt+branch select (a swapped-arm textual repeat)
|
|
-> agent tell-cards (the §172b cookbook text rides on the card)
|
|
- frac > 0.35 -> redraft (SIZE-MISMATCH — the draft is not the function)
|
|
|
|
Detectors are IMPORTED from atlas_features (one implementation, R33).
|
|
"""
|
|
import os, sys
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
import family_align as FA
|
|
from atlas_features import extpair_count, dupselect_count
|
|
|
|
COOKBOOK = {
|
|
"EXTPAIR": "§172b-1: the target's extra sll/sra-16|24 pair = a REGISTER-held short promotion "
|
|
"(a multi-def s16/s8 variable, e.g. branch-merged); keep the short in a named local "
|
|
"used both ways so the promotion pair exists.",
|
|
"SELECT": "§172b-2: the target's extra slt+branch+move select = the source textually REPEATED "
|
|
"a compare with SWAPPED arms ((b>a)?b:a vs (a<b)?a:b); repeat the expression with "
|
|
"swapped operands at the extra site.",
|
|
"NOP": "schedule artifact — route to the permuter length profile, not an edit.",
|
|
}
|
|
|
|
|
|
def analyze(mine_words, tgt_words):
|
|
"""-> card dict {verdict, delta, frac, clusters, tells, blocks, route}."""
|
|
delta = len(tgt_words) - len(mine_words)
|
|
frac = abs(delta) / max(1, len(tgt_words))
|
|
verdict, detail = FA.classify_aligned(mine_words, tgt_words)
|
|
|
|
tells = []
|
|
blocks = []
|
|
if verdict in ("LEN-STRUCT", "STRUCT-ALIGNED"):
|
|
ops = FA.align_blocks(mine_words, tgt_words)
|
|
for tag, i1, i2, j1, j2 in ops:
|
|
if tag == "equal":
|
|
continue
|
|
tw = tgt_words[max(0, j1 - 2):min(len(tgt_words), j2 + 2)]
|
|
kinds = []
|
|
if extpair_count(tw):
|
|
kinds.append("EXTPAIR")
|
|
if dupselect_count(tgt_words[max(0, j1 - 8):min(len(tgt_words), j2 + 8)]):
|
|
kinds.append("SELECT")
|
|
if all(w == 0 for w in tgt_words[j1:j2]) and i1 == i2:
|
|
kinds.append("NOP")
|
|
blocks.append({"mine": [i1, i2], "tgt": [j1, j2], "kinds": kinds,
|
|
"tgt_words": [f"{w:08x}" for w in tgt_words[j1:j2][:12]]})
|
|
tells += kinds
|
|
clusters = [(hex(a), hex(b)) for a, b, _ in detail.get("clusters", [])]
|
|
|
|
if frac > 0.35:
|
|
route = "redraft"
|
|
elif verdict == "LEN-LI" and clusters and all(a != b for a, b in clusters):
|
|
route = "mechanical"
|
|
elif verdict == "LEN-NOP" or (verdict.startswith("LEN") and abs(delta) <= 2 and not tells):
|
|
route = "permuter-length"
|
|
elif tells:
|
|
route = "tell-card"
|
|
elif verdict in ("PURE", "IMM"):
|
|
route = "imm-or-reloc" # equal length reached here = not a LEN case at all
|
|
else:
|
|
route = "card"
|
|
return {"verdict": verdict, "delta": delta, "frac": round(frac, 3),
|
|
"clusters": clusters, "tells": sorted(set(tells)),
|
|
"tell_refs": [COOKBOOK[t] for t in sorted(set(tells)) if t in COOKBOOK],
|
|
"blocks": blocks[:8], "route": route,
|
|
"detail": detail if route == "mechanical" else None}
|
|
|
|
|
|
def repair_mechanical(draft_text, mine_words, tgt_words, detail):
|
|
"""Swap the draft's cluster/imm literals toward the target's. -> (new_text, unresolved)."""
|
|
return FA.imm_map_aligned(draft_text, mine_words, tgt_words, detail)
|