diff --git a/docs/matching-cookbook.md b/docs/matching-cookbook.md index 081d0ec9c..5af7662eb 100644 --- a/docs/matching-cookbook.md +++ b/docs/matching-cookbook.md @@ -7538,3 +7538,52 @@ miss it (the T24 `--allow-pins` precedent). `--no-tu-scope` exists to A/B it. written N times — delete all N. Now it compares whitespace-collapsed forms and refuses only on a genuine disagreement. (Measured on `D_800B9A02`: 3 decls in **2 different forms** — so that one was correctly refused, and the relaxation did not paper over a real conflict.) + +--- + +## §108 — Diagnosing a family `0/N`: the four causes, and the third opt-in lever (Phase 29 T59) + +A family sweep's `0/N` says nothing about the code until you splice ONE member and read the compiler. +Do it like this — the shape of the output actively hides the answer: + +``` +make -j1 build/ BINARY= # -j16 interleaves the real error out of reach +# then filter: '.c:' in line AND 'warning:' not in line +``` +The `memcpy` / `type mismatch with previous external decl` warnings (§58) are noise from unrelated +TU positions and will dominate any naive tail. And `set -o pipefail` (§93) attributes the failure to +the last pipeline stage, so "Error 1"/"Error 33" names the wrong stage — read cc1's own lines. + +**The verdict split that matters is PLUMBING vs DIFF**: a compile error is a declaration problem +(recoverable, and each has a named lever); a clean compile with differing bytes is codegen. Five +families diagnosed this way resolved to **four distinct causes**, only one of which is a wall: + +| cause | signature | lever | +|---|---|---| +| shared-header signature conflict | `conflicting types for func_X`, "previous declaration" points at a **`DEFINE_func_*()` macro line** | `--fix-def-sig` (see the bug below) | +| PsyQ/library symbol conflict | `conflicting types for ApplyMatrixSV` | unresolved — the draft's carried decl vs the TU's | +| genuine codegen | compiles clean, bytes differ | permuter / §31 lookup | +| no matched exemplar | `remap: no matched unit` | not a blocker — the family has no fuel | + +**Read the "previous declaration" line number before theorising.** For `func_8014D610` it pointed at +line 1727, which is not a declaration at all — it is `DEFINE_func_8014D438()`, a shared-macro +instantiation whose expansion forward-declares the templated function with the canonical +`engine_core.h` signature. cc1 reports the conflict at the macro's line. That one line identifies the +whole class. + +**THE `--fix-def-sig` BUG (why the lever did not fire).** `reconcile_def_sig` rewrites the draft's +definition to the canonical header decl **wholesale — types AND parameter names**: + +``` +canonical : void func_8014D610(s32 a0, void *a1, void *a2) +draft body: ... param_1 ... param_2 ... -> `param_1' undeclared +``` +Its docstring calls this a "rare name mismatch" that "the gate rejects, never a false bank". It is +**not rare** — an exemplar drafted with the `param_N` convention hits it every time, and the whole +family books as a compile failure. **The fix is to conform the TYPES and keep the BODY's names**; +both are already in hand at the call site. + +> **The law:** three times in one session a family-wide `0/N` was a lever that was unreachable +> (§107), off by default, or subtly broken — never the compiler. **Before diagnosing a family as +> hard, enumerate the levers the invocation actually enabled, then read one member's real cc1 +> output.** A sweep's `0/N` is a statement about the harness. diff --git a/phase-ends/CURRENT_PHASE.md b/phase-ends/CURRENT_PHASE.md index b71261ad4..cdff7b89b 100644 --- a/phase-ends/CURRENT_PHASE.md +++ b/phase-ends/CURRENT_PHASE.md @@ -8069,3 +8069,64 @@ recount agrees exactly (T52 132 · T56 136 · T57 132 · T58 137). **+67,666 ins measurements themselves are still old; a re-collect is owed before the grinder is trusted again. **DO NOT close P29 on ROI** — +0.5pp instr today, and item 1 is a diagnosis queue with ~50 families behind it, not a burn-down floor. + +## 🔎 T59 — the five T58 zero families diagnosed: **four distinct causes, only one is a wall** + +Deliverable is the diagnosis, not banks. Method: splice ONE member, `make -j1` the single object, +read the **non-warning** cc1 lines (the `-j16` interleave and the §58 `memcpy`/`type mismatch` +warnings hide the real line every time; §93 pipefail names the wrong stage). Tree verified clean +after every probe. + +### FIRST, A CORRECTION TO MY OWN T58 REPORT (R14) +I said "7 remaining families all have banked exemplars". **Wrong — there were 5.** `0x80175820` +(276 members) and `0x8016ec0c` (138) have **no matched exemplar anywhere**: both are INCLUDE_ASM +stubs in all 138 overlays. My T58 batch-selection test picked the first TU *containing the name* — a +declaration — and, seeing no stub in that file, called it banked. **The family map was right all +along** (`kind: 'draft-ov077'`, `matched_members: []`) and `family_sweep` correctly excluded them +("6 matched-exemplar families", a line I read past). The oracle to use is `corpus.stubs(ov)`, never +a name-grep. Their claimed weight (60,720 + 48,576 bytes) was never real fuel. + +### THE FIVE VERDICTS +| family | members | verdict | cause | +|---|---|---|---| +| `0x8014d610` | 137 | PLUMBING | shared-header signature conflict | +| `0x8016163c` | 137 | PLUMBING | shared-header signature conflict | +| `0x80156044` | 137 | PLUMBING | shared-header signature conflict | +| `0x80143d28` | 136 | PLUMBING | `conflicting types for **ApplyMatrixSV**` — a PsyQ library symbol | +| `0x801457a4` | 137 | **DIFF** | compiles clean, bytes differ — **the only genuine codegen wall** | + +### THE HEADER-CONFLICT CLASS (3 families / 411 members ≈ 30,000 ins) — AND A THIRD OPT-IN LEVER +The "previous declaration" line was the tell: for `func_8014D610` it pointed at line 1727, which is +**not a declaration** — it is `DEFINE_func_8014D438()`, a shared-macro instantiation whose expansion +forward-declares the templated function with the canonical `engine_core.h` signature. Verified all +four are header-declared with a signature that disagrees with the exemplar's def; the two non-header +families are exactly the two with different verdicts. + +`--fix-def-sig` is the lever for this — **a third opt-in one** (after T56's unreachable and T57's +off-by-default). Tested it: **0/411, and the verdict did NOT move to DIFF** — it moved to a +different, precise compile error: +``` +canonical : void func_8014D610(s32 a0, void *a1, void *a2) +draft body: ... param_1 ... -> `param_1' undeclared (first use this function) +``` +**`reconcile_def_sig` adopts the canonical signature wholesale — types AND parameter names — while +the body keeps the exemplar's `param_N` names.** Its docstring calls this a "rare name mismatch"; +it is not rare — an exemplar drafted with the `param_N` convention hits it every time and the whole +family books as a compile failure. **Fix: conform the TYPES, keep the BODY's names** (both are in +hand at the call site). + +### THE PATTERN, THREE TIMES IN ONE SESSION +T56 a lever unreachable from the sweep path · T57 a lever off by default · T59 a lever subtly broken. +**Every family-wide `0/N` so far has been a statement about the harness, not the code.** Cookbook +**§108** records the diagnosis recipe + the four causes so this is a lookup next time. + +## ▶ NEXT (ranked, all measured) +1. **Fix `reconcile_def_sig`'s param-name bug** (conform types, keep body names) and re-sweep the 3 + header-conflict families — **411 members ≈ 30,000 ins**, the largest measured, best-understood + block on the board. +2. **`0x80143d28`** (136) — `ApplyMatrixSV` conflict: the draft's carried decl of a PsyQ symbol vs + the TU's. Likely the same shape one level out; one probe. +3. **`0x801457a4`** (137) — the only true DIFF; measure closeness and route per §31. +4. **Probe the distinct-code +0 anomaly** (4 data points, no identified variable). +5. **~50 more eligible families** — regenerate `family_hseq.py` first (the map predates T56–T58), and + select exemplars with **`corpus.stubs`**, not a name-grep.