mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-26 21:36:06 -04:00
fix(phase-29): T54 — correct the ADDRESSING route, and fix the reason changing it was inert
Item 1 off T53's list. Two changes: the route, and the design flaw underneath it.
THE DEFECT UNDER THE DEFECT (cookbook §106). residual_class answers two questions in one pass:
`klass` is a MEASUREMENT (expensive, from comparing instruction streams); `(profile, bucket)` is a
POLICY (a table lookup over it). autopsy persisted BOTH and verdicts() read BOTH back — so editing
_ROUTE changed nothing until someone re-ran the whole collect, and a weeks-old row could silently
out-vote the live table with no oracle to report it. The corpus on disk is dated Jul 21 and does not
even contain the SESSION-23 targets the recommendation cited.
Fixed by re-deriving at read time: residual_class.route_for(klass, detail), called from
autopsy.verdicts(). R33 — persist the measurement, derive the decision. Subtlety: LENGTH-DRIFT's
route is MAGNITUDE-dependent (permuter only when |delta|<=2 AND explains=="tail", §60b), so a naive
re-derivation from klass alone would have silently demoted 9 rows; both inputs are already in
`detail`, so the override reproduces exactly — VERIFIED 1610/1610 against the stored corpus with the
table UNCHANGED, before touching it.
THE ROUTE CHANGE: ADDRESSING ("cse","permuter") -> ("cse","structural"). It contradicted this file's
own bucket definition ("structural — local mutation CANNOT introduce it ... it wants a C-level
idiom"): the §10/§20 hoist-vs-remat shape is a multi-instruction change with a documented recipe
(gcc-2.7.2-map/cse_expr.md §2, byte-proven on func_80149374/func_801493D0). Measured (T31): both
admitted ADDRESSING targets plateaued under a §31-directed permuter, and the class was 32% of the
admission pool. After: pool 56 -> 38, exactly 18 rows changed, ALL ADDRESSING, nothing else moved;
grinder admits 45, structural skips 512 -> 530.
THE BOUND (R14), kept in the _ROUTE comment: I read the T31 record instead of the summary line, and
the summary was looser than the evidence. T31 finding 4 byte-tested the §2 recipe on func_80132F40
across six variants and it never closed (best 40 mismatches). `structural` does NOT promise a free
fix — it means "a search over local mutations is the wrong tool, try the documented idiom", exactly
what WIDTH / BRANCH-POLARITY / IMM-OFFSET already mean. Also corrected: the checkpoint cited
func_80176734 as the flat-for-32-min evidence, but that function is not in the corpus at all.
Tooling-only: no src/ or config/ change, no bank, no metric move.
This commit is contained in:
@@ -7457,3 +7457,46 @@ Negative-control proven: the same crashing invocation now reports `{'exception':
|
||||
> through it. Same family as §97 (the gate's own tree hygiene), and the reason it matters more in a
|
||||
> sweep than in a one-off: a one-off's residue is visible in the next `git status`; a sweep's residue
|
||||
> is consumed by the next iteration first.
|
||||
|
||||
---
|
||||
|
||||
## §106 — Persist the MEASUREMENT, derive the POLICY: a stored route let a stale file out-vote the live table (Phase 29 T54, `residual_class._ROUTE`)
|
||||
|
||||
`residual_class` answers two different questions in one pass. **`klass`** is a *measurement* — it comes
|
||||
from comparing two instruction streams and is expensive. **`(profile, bucket)`** is a *policy* — a table
|
||||
lookup over `klass` that says which tool should work on it. `autopsy` persisted both to
|
||||
`.run/autopsy/residuals.jsonl`, and `verdicts()` read both back.
|
||||
|
||||
That made the corpus authoritative for a decision the table owns, with two consequences:
|
||||
|
||||
* **a route correction was inert.** Editing `_ROUTE` changed nothing until someone re-ran the whole
|
||||
collect — so the fix and its effect were separated by an expensive step that is easy to skip.
|
||||
* **a weeks-old row could silently contradict the live table**, and nothing would ever report the
|
||||
disagreement (there is no oracle comparing a stored policy against the current one — R34's blind spot).
|
||||
|
||||
**The fix: re-derive the route at read time from the stored `klass` + `detail`.** The measurement stays
|
||||
persisted; the policy is looked up fresh on every read.
|
||||
|
||||
The subtlety that makes this a technique rather than a one-liner: **one route is magnitude-dependent.**
|
||||
`LENGTH-DRIFT` is permuter-shaped only when `|delta| <= 2 AND explains == "tail"` (§60b). A naive
|
||||
re-derivation from `klass` alone would silently demote those rows. Both inputs are already in `detail`,
|
||||
so `route_for(klass, detail)` reproduces the override exactly — **verified at 1610/1610 against the
|
||||
stored corpus with the table UNCHANGED, before the table was edited.** Prove the derivation is faithful
|
||||
first, then change the policy; otherwise a bug in the derivation is indistinguishable from the intended
|
||||
change.
|
||||
|
||||
**The route change itself (the reason this came up):** `ADDRESSING` was routed to the permuter, which
|
||||
contradicted `residual_class`' own bucket definition — *"structural — local mutation CANNOT introduce
|
||||
it … it wants a C-level idiom."* The §10/§20 hoist-vs-remat shape is a multi-instruction change with a
|
||||
documented deterministic recipe (`gcc-2.7.2-map/cse_expr.md` §2). Measured: both admitted ADDRESSING
|
||||
targets plateaued under a §31-directed permuter, and the class was **32% of the entire admission pool
|
||||
(18 of 56)**. After the fix: **56 → 38**, exactly 18 rows changed, all ADDRESSING, nothing else moved.
|
||||
|
||||
**And the bound, kept in the comment where the next reader will hit it:** T31's finding 4 byte-tested
|
||||
the §2 recipe on `func_80132F40` across six variants and it never closed. `structural` here does not
|
||||
promise a free fix — it means *"a search over local mutations is the wrong tool; try the documented
|
||||
idiom"*, exactly what WIDTH / BRANCH-POLARITY / IMM-OFFSET already mean.
|
||||
|
||||
> **The law:** persist what was *measured*; derive what was *decided*. If a stored field can be
|
||||
> recomputed from other stored fields plus a table, storing it converts a future correction into a
|
||||
> silent no-op — and the staler the file, the more confidently it lies.
|
||||
|
||||
@@ -7723,3 +7723,50 @@ sweep is the true end-to-end validation.
|
||||
Discount its 37,536 headline: it is `_o0`, and `_o0` families sweep ~1/137.
|
||||
4. **PARKED: `func_80176734`** (51,198 ins) — five tiers bounced; clusters A and B are provably
|
||||
coupled and must be solved together.
|
||||
|
||||
## ✅ T54 — the `ADDRESSING` route corrected, and the reason it was inert fixed underneath it
|
||||
|
||||
Item 1 off T53's list. Two changes: the route itself, and the design flaw that would have made
|
||||
changing it a no-op.
|
||||
|
||||
### THE DEFECT UNDER THE DEFECT (§106)
|
||||
`residual_class` answers two different questions in one pass: **`klass`** is a *measurement*
|
||||
(expensive, from comparing instruction streams) and **`(profile, bucket)`** is a *policy* (a table
|
||||
lookup over it). `autopsy` persisted BOTH and `verdicts()` read BOTH back. So editing `_ROUTE`
|
||||
changed nothing until someone re-ran the whole collect, and a weeks-old row could silently
|
||||
out-vote the live table with no oracle to report the disagreement. **The corpus on disk is dated
|
||||
Jul 21 — it does not even contain the SESSION-23 targets the recommendation cited.**
|
||||
|
||||
Fixed by re-deriving the route at read time (`route_for(klass, detail)`; R33 — persist the
|
||||
measurement, derive the decision). The subtlety: one route is **magnitude-dependent** —
|
||||
`LENGTH-DRIFT` is permuter-shaped only when `|delta| ≤ 2 AND explains == "tail"` (§60b), so a naive
|
||||
re-derivation from `klass` alone would have silently demoted those 9 rows. Both inputs are already
|
||||
in `detail`, so the override reproduces exactly — **verified 1610/1610 against the stored corpus
|
||||
with the table UNCHANGED, before touching it.** Proving the derivation faithful first is what makes
|
||||
the subsequent diff interpretable.
|
||||
|
||||
### THE ROUTE CHANGE
|
||||
`ADDRESSING: ("cse", "permuter") → ("cse", "structural")`. It contradicted `residual_class`' own
|
||||
bucket definition — *"structural — local mutation CANNOT introduce it … it wants a C-level idiom."*
|
||||
The §10/§20 hoist-vs-remat shape is a multi-instruction change with a documented deterministic
|
||||
recipe (`gcc-2.7.2-map/cse_expr.md` §2, byte-proven on `func_80149374`/`func_801493D0`).
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| measured corroboration (T31) | both admitted ADDRESSING targets (`func_80140958`, `func_80177B5C`) plateaued under a §31-directed permuter |
|
||||
| share of the admission pool | **18 of 56 = 32%** |
|
||||
| after the fix | pool **56 → 38**; exactly **18** rows changed, **all** ADDRESSING, nothing else moved |
|
||||
| grinder smoke | admits 45; `structural` skip-count 512 → 530 |
|
||||
|
||||
### THE BOUND, KEPT WHERE THE NEXT READER HITS IT (R14)
|
||||
I checked the T31 record rather than the summary line, and the summary was looser than the evidence.
|
||||
T31 finding 4 **byte-tested** the §2 recipe on `func_80132F40` across six variants — it never closed
|
||||
(best 40 mismatches). So `structural` here does **not** promise a free fix; it means *"a search over
|
||||
local mutations is the wrong tool, try the documented idiom"* — exactly what WIDTH /
|
||||
BRANCH-POLARITY / IMM-OFFSET already mean. That caveat is in the `_ROUTE` comment, not just here.
|
||||
Also corrected: the checkpoint line cited `func_80176734` as the flat-for-32-min evidence, but that
|
||||
function is **not in the corpus at all** — the two targets that actually plateaued are the ones above.
|
||||
|
||||
### GATE
|
||||
Tooling-only, no `src/`/`config/` change → no bank, no metric move. `parse OK` on both edited tools;
|
||||
the effect measured directly through `autopsy.verdicts()` and `grinder.candidates()`.
|
||||
|
||||
+10
-1
@@ -189,7 +189,15 @@ def verdicts():
|
||||
|
||||
The consumer-facing accessor (tools/grinder.py). Returns {} rather than raising so a missing
|
||||
corpus degrades to the previous undirected behaviour instead of breaking the daemon — but the
|
||||
caller must SAY which mode it is in (R32: a filter that silently does nothing is the defect)."""
|
||||
caller must SAY which mode it is in (R32: a filter that silently does nothing is the defect).
|
||||
|
||||
THE ROUTE IS RE-DERIVED HERE, NEVER READ FROM THE FILE (R33, Phase 29 T54). `klass` is the
|
||||
measurement and is trusted; `profile`/`bucket` are a policy lookup over it, and a stored lookup
|
||||
output makes a weeks-old file authoritative for a decision `residual_class._ROUTE` owns — a
|
||||
route correction would be inert until someone re-ran the whole collect, and the stale row would
|
||||
silently out-vote the live table. `route_for` reproduces the stored routes exactly under an
|
||||
unchanged table (verified 1610/1610), so this is a no-op except where the table has since been
|
||||
corrected — which is precisely when it must not be a no-op."""
|
||||
p = os.path.join(REPO, OUT)
|
||||
if not os.path.exists(p):
|
||||
return {}
|
||||
@@ -198,6 +206,7 @@ def verdicts():
|
||||
if line.strip():
|
||||
r = json.loads(line)
|
||||
if r.get("name") and r.get("klass"):
|
||||
r["profile"], r["bucket"] = residual_class.route_for(r["klass"], r.get("detail"))
|
||||
out[r["name"]] = r
|
||||
return out
|
||||
|
||||
|
||||
+38
-2
@@ -42,7 +42,8 @@ unclassifiable residual is `UNKNOWN`, COUNTED, never silently bucketed, R32):
|
||||
REGALLOC-LOCAL register-only diffs, no consistent global map -> regalloc
|
||||
WIDTH load/store WIDTH flip (lw↔lh↔lb, sw↔sh↔sb) -> structural (idiom)
|
||||
STRENGTH mult/div ↔ shift/add re-association -> cse
|
||||
ADDRESSING addu/addiu/lui base-address shape (§10 hoist-vs-remat) -> cse
|
||||
ADDRESSING addu/addiu/lui base-address shape (§10 hoist-vs-remat) -> structural (idiom:
|
||||
cse_expr.md §2's remat kill) — NOT permuter fuel, see _ROUTE
|
||||
BRANCH-POLARITY beq↔bne / bgez↔bltz (loop-guard operand order) -> structural (idiom)
|
||||
OPCODE-MIXED different operations, no single family -> structural
|
||||
IMM-OFFSET same ops+regs, immediates differ by a CONSTANT (a frame -> structural
|
||||
@@ -154,7 +155,19 @@ _ROUTE = {
|
||||
"REGALLOC-LOCAL": ("regalloc", "permuter"),
|
||||
"WIDTH": (None, "structural"),
|
||||
"STRENGTH": ("cse", "structural"),
|
||||
"ADDRESSING": ("cse", "permuter"),
|
||||
# ADDRESSING was ("cse", "permuter") and that contradicted this file's OWN bucket definition:
|
||||
# "structural — local mutation CANNOT introduce it ... it wants a C-level idiom". The §10/§20
|
||||
# hoist-vs-remat shape (a base address kept in a callee-saved reg vs recomputed per use) is a
|
||||
# multi-instruction change, not a local mutation, and `gcc-2.7.2-map/cse_expr.md` §2 documents
|
||||
# a deterministic C recipe for it (the output-only `__asm__ __volatile__("" : "=r"(q))` kill),
|
||||
# byte-proven on func_80149374 / func_801493D0. Measured corroboration (Phase 29 T31): BOTH
|
||||
# admitted ADDRESSING targets (func_80140958, func_80177B5C) plateaued under a §31-directed
|
||||
# permuter, and it was 32% of the whole permuter admission pool (18 of 56).
|
||||
# BOUNDED, and the bound is byte-tested (T31 finding 4): the §2 recipe does NOT dissolve every
|
||||
# hoist — func_80132F40 took 6 variants to 40 mismatches and never closed. So `structural` here
|
||||
# does not promise a free fix; it means "a search over local mutations is the wrong tool, try the
|
||||
# documented idiom" — exactly what WIDTH / BRANCH-POLARITY / IMM-OFFSET already mean.
|
||||
"ADDRESSING": ("cse", "structural"),
|
||||
"BRANCH-POLARITY": (None, "structural"),
|
||||
"OPCODE-MIXED": (None, "structural"),
|
||||
"IMM-OFFSET": (None, "structural"),
|
||||
@@ -457,6 +470,29 @@ def _drift_route(d, explains="partial"):
|
||||
return {"profile": "length", "bucket": "permuter"} if (abs(d) <= 2 and explains == "tail") else {}
|
||||
|
||||
|
||||
def route_for(klass, detail=None):
|
||||
"""The CURRENT route for a stored verdict — `(profile, bucket)` derived from `klass` + `detail`.
|
||||
|
||||
THE ROUTE IS A POLICY, NOT A MEASUREMENT (R33). `klass` is the expensive part: it comes from
|
||||
comparing two instruction streams. The route is a table lookup over it. Persisting the lookup's
|
||||
OUTPUT (as `.run/autopsy/residuals.jsonl` did) makes a stale corpus authoritative for a decision
|
||||
the table owns — so correcting `_ROUTE` was inert until someone re-ran the whole collect, and a
|
||||
stored row could silently contradict the live table. Consumers now re-derive at read time
|
||||
(`autopsy.verdicts`), so a route correction takes effect immediately and cannot be out-voted by
|
||||
a file written weeks ago.
|
||||
|
||||
Faithful to the magnitude-dependent override: LENGTH-DRIFT's route depends on `delta`/`explains`,
|
||||
and both are persisted in `detail`, so this reproduces `_drift_route` exactly rather than
|
||||
approximating it. Verified against the stored corpus at 1601/1601 before `_ROUTE` was edited."""
|
||||
prof, bkt = _ROUTE[klass]
|
||||
d = detail or {}
|
||||
if klass == "LENGTH-DRIFT" and "delta" in d:
|
||||
ov = _drift_route(d["delta"], d.get("explains", "partial"))
|
||||
if ov:
|
||||
prof, bkt = ov["profile"], ov["bucket"]
|
||||
return prof, bkt
|
||||
|
||||
|
||||
def _v(klass, closeness, nm, nt, detail, sig=None, profile=_KEEP, bucket=_KEEP):
|
||||
"""`profile`/`bucket` override the static _ROUTE entry for the cases where the ROUTE depends on
|
||||
the residual's MAGNITUDE, not just its kind — LENGTH-DRIFT being the one that matters: a ±1-2
|
||||
|
||||
Reference in New Issue
Block a user