Files
BFM-decomp/docs/autopsy.md
T
Drew T b3ab5c2253 feat(phase-29 Task-13A): deterministic residual classifier — the permuter's problem is TARGETING
The autopsy (hindsight-study §7) assumed the permuter loses for want of a mutation.
Measured over the whole open backlog, it loses because it is aimed at work a
search-closer provably cannot close.

- NEW tools/residual_class.py: decide a near-miss's class FROM THE BYTES. Decodes each
  mismatching MIPS word -> (op-skeleton, register-fields, immediate); drift FIRST (one
  inserted insn inflates `closeness` by the tail length), then consistent-injective
  register map -> REGALLOC-PERM (§31 S11/RC-3), same-multiset-reorder -> SCHEDULE-REORDER,
  DELAY-SLOT, WIDTH/BRANCH-POLARITY/STRENGTH/ADDRESSING/IMM-OFFSET/IMM-VALUE. Every class
  routes to a BUCKET = which tool the failure wants. Uncovered opcode -> UNKNOWN, COUNTED
  (R32). 16 synthetic unit tests (test_residual_class.py).
- NEW tools/autopsy.py: `collect` materialises the corpus Task-12's telemetry never filled
  (1 of 6,169 records had a residual) by recompiling every open draft through the EXISTING
  match_one path (R33) — 1,752 drafts in 21s at -j12. `report` -> docs/autopsy.md.
- NEW corpus.o0_sources()/is_o0(): the opt-level oracle DERIVED from the Makefile's own -O0
  rules, coverage-asserted. Scoring an -O0 target at -O2 makes the residual 100% artefact
  (the trap this phase hit four times).
- R34 cross-check baked in: residual_class's closeness vs masked_diff.structured_diff's,
  asserted per row; 1,673/1,673 agree, 0 classifier errors.

FINDING: of the 972 records the grinder's own filter admits, only 75 (7.7%) are
permuter-shaped; 547 are structural and 348 are drafts that are not the function at all.
~92% of the daemon's CPU went where it could not win — the byte-grounded explanation of
"7 banks all-time, all Phase 21, 0 since" (Phase-22 audit). grinder.candidates() now
filters on the measured bucket (1,303 -> 78) and takes its directed profile from the
measured class, not the logged label (91% carry none -> it ran on gcc defaults).
Degrades to undirected if uncollected and says so; --no-targeting A/Bs it.

Two measured corollaries (R14, not projections):
- 699 records rank as near-misses at closeness up to 278 purely from a length artefact:
  un-attempted work misfiled as a backlog of hard functions -> new `redraft` bucket.
- a 12-draft gate probe of the `integration` bucket banked 1/12 (11 PLUMBING), so the 306
  prices Task 14's reconcile ladder rather than promising free banks. func_80167714
  (104 ins, reach-134) banked x1, un-propagated by design (§55b).

Two defects fixed forward:
- masked_diff._common_typedefs() used ONE shared probe path, so parallel match_one
  processes clobbered each other: 14 of 1,752 drafts lost in a single 12-way run (0.8%),
  silently, in every parallel wave ever run. Now per-PID.
- gate_stage.match_one_closeness never passed --o0 -> phantom residuals for every -O0
  function, written straight into the backlog this autopsy reads.

R22 clean-fleet: check-all 140 passed, 0 failed of 140; tools-health OK (dedup 1847/0,
C1 234343/234343); 0 NON_MATCHING (G4). Flywheel captured in-session (R30/R31):
cookbook §60, decision-log entry, SETUP.md inventory.
2026-07-21 11:03:59 -06:00

4.1 KiB

Autopsy — the permuter's failures, classified

Generated by tools/autopsy.py report from .run/autopsy/residuals.jsonl (built by collect, which recompiles every open backlog draft through tools/match_one.py and classifies the FULL residual with tools/residual_class.py).

A verdict here is a candidate, never a bank: the whole-binary byte-gate remains the sole arbiter (G3/P9).

Corpus: 1752 record(s) · 1659 classified · status {'near': 1354, 'nobuild': 93, 'match': 305}

Buckets — what tool each failure actually wants

bucket fns reach-weighted meaning
redraft 699 2162 the stored draft is NOT this function — un-attempted work misfiled as a near-miss; route to a fresh crack, not to a wall
structural 578 7761 local mutation CANNOT introduce it — wants a C-level idiom, not CPU
integration 305 2303 byte-correct standalone; blocked on plumbing (§58/§59 reconcile ladder)
permuter 75 740 local mutation CAN reach it — permuter fuel (a plateau here is a missing-transform candidate)
unknown 2 2 the residue the LLM tier is for

Classes

class fns reach-weighted bucket permuter profile
SIZE-MISMATCH 699 2162 redraft —
LENGTH-DRIFT 394 6380 structural —
MATCH 305 2303 integration —
OPCODE-MIXED 80 878 structural —
WIDTH 44 310 structural —
IMM-OFFSET 38 38 structural —
DELAY-SLOT 23 289 permuter schedule
BRANCH-POLARITY 22 155 structural —
REGALLOC-PERM 18 151 permuter regalloc
ADDRESSING 17 150 permuter cse
IMM-VALUE 10 143 permuter cse
SCHEDULE-REORDER 7 7 permuter schedule
MIXED 2 2 unknown —

Top clusters (the batch-autopsy work items)

One representative per signature diagnoses the whole cluster — that is what makes the LLM pass a batch autopsy rather than N per-function reads.

# signature fns reach-weighted example
1 SIZE-MISMATCH/short 604 1801 func_8017E918 (close=4, 2 ins)
2 MATCH 305 2303 func_80168B70 (close=0, 27 ins)
3 LENGTH-DRIFT/-1? 116 1712 func_8018312C (close=5, 7 ins)
4 SIZE-MISMATCH/long 95 361 func_8017E06C (close=6, 9 ins)
5 LENGTH-DRIFT/-2? 70 1268 func_80190480 (close=3, 4 ins)
6 OPCODE-MIXED 67 599 func_80161D20 (close=1, 14 ins)
7 LENGTH-DRIFT/1? 63 595 func_80187074 (close=4, 7 ins)
8 LENGTH-DRIFT/2? 51 450 func_80181B8C (close=5, 11 ins)
9 LENGTH-DRIFT/-7 32 32 func_80184590 (close=9, 2 ins)
10 LENGTH-DRIFT/+1 21 21 func_8017DCE4 (close=3, 8 ins)
11 IMM-OFFSET/1 17 17 func_801827C4 (close=1, 13 ins)
12 DELAY-SLOT/1 13 146 func_8016BA68 (close=1, 29 ins)
13 BRANCH-POLARITY/bnez!=beqz 11 144 func_80185E38 (close=1, 12 ins)
14 IMM-VALUE 10 143 func_8018A640 (close=2, 4 ins)
15 WIDTH/lhu!=lh 9 9 func_80142A10 (close=1, 28 ins)
16 LENGTH-DRIFT/-3? 8 1072 func_8012CC88 (close=13, 102 ins)
17 OPCODE-MIXED/addressing,width 8 274 func_8017F114 (close=5, 75 ins)
18 DELAY-SLOT/2 8 141 func_80158638 (close=2, 87 ins)

Second oracle — deterministic verdict vs the recorded label

The recorded klass is what a wave agent typed months ago; the verdict is derived from today's bytes. Neither is authoritative — the disagreement is the finding, and it is exactly the mis-classified bucket (a wrongly-labelled residual sends the directed search at the wrong levers, so it plateaus and then reads as a wall).

  • labelled records comparable: 4 · agree 3 · disagree 1
fn recorded label label routes to measured class measured routes to
func_801549F8 schedule schedule ADDRESSING cse