docs(phase-29): T59 — the five T58 zero families diagnosed: four causes, one wall

Deliverable is the diagnosis, not banks. Method: splice ONE member, `make -j1` the single object,
read the NON-warning cc1 lines (-j16 interleaves the real error away; the §58 memcpy / "type
mismatch" warnings dominate any naive tail; §93 pipefail names the wrong stage). Tree clean after
every probe.

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: INCLUDE_ASM stubs in all 138 overlays. My 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). Use corpus.stubs(ov), never a name-grep.
Their claimed 109,296 bytes were never real fuel.

THE FIVE VERDICTS:
  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) + A THIRD OPT-IN LEVER. The
"previous declaration" line was the tell: for func_8014D610 it points at line 1727, which is NOT a
declaration — it is DEFINE_func_8014D438(), a shared-macro instantiation whose expansion
forward-declares the templated fn with the canonical engine_core.h signature. All four conflicting
fns are header-declared; the two non-header families are exactly the two with different verdicts.
--fix-def-sig is the lever (a THIRD opt-in one, after T56's unreachable and T57's off-by-default).
Tested: 0/411, and the verdict did NOT move to DIFF — it moved to a precise new compile error:
  canonical : void func_8014D610(s32 a0, void *a1, void *a2)
  draft body: ... param_1 ...   ->  `param_1' undeclared
reconcile_def_sig adopts the canonical signature WHOLESALE (types AND param 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. Fix: conform TYPES, keep BODY
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 recipe + the four causes.

No src/ or config/ change: no bank, no metric move.
This commit is contained in:
Drew T
2026-07-28 21:04:40 -06:00
parent fa6d9c88e6
commit 28ef237c35
2 changed files with 110 additions and 0 deletions
+49
View File
@@ -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/<the one .o> BINARY=<ov> # -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.
+61
View File
@@ -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.