fix(phase-30 S33b): the PAIR rule — my 42-decl relax did NOT unblock the lane; the mirror form did

HONEST CORRECTION to commit:1382. That commit's message implies the 42 `(void)`
relaxes unblocked the PROPAGATE remainder. They did NOT: the re-run banked 0/1
in all 134 overlays with the same error, because DEFINE_func_8016BA68 declares
func_80146C3C `(u8*)` — the MIRROR of the EXTEND-lane pair — and my relax only
touched the `(void)` direction.

Root cause is the R37 shape a third time: I bucketed by SYMBOL and stopped. The
lever is set by the (macro-shape, TU-shape) PAIR, and the same symbol conflicts
in BOTH directions across this fleet. One awk over the macro I was ACTUALLY
fixing — which I ran for the EXTEND macros and not for this one — shows the pair
before a 134-build run. §138 amended with the PAIR rule; correction logged in
CURRENT_PHASE.md rather than rewritten out of history.

The 42-decl relax still stands: byte-neutral, R22 140/140, removes a real
conflict class. It just did not do what I predicted.

THIS commit relaxes the 2 remaining `(u8*)` decls (uses are cast; `()` is
compatible with the (void)/()/(u8*) forms the fleet carries and no decl of this
symbol has a default-promotion param). R22 clean-fleet: 140 passed, 0 failed.

ALSO: tools/overlay_src_split.py `_split_macro_body` — the §134 sweep's one real
target, fixed. It carried the identical single-line-only comment test, and it
decides where a macro body's file-scope externs END, so a multi-line comment
truncated the extern set. SIZED FIRST: 38 live lines in engine_core.h macro
bodies hit it today. Now decides on cdecl._mask (one oracle, R33) with the
length-preservation invariant asserted (R32). Proven both directions by a
control: pre-fix it stopped at `/* multi` carrying 1 of 2 externs and treated the
comment as the definition head; post-fix both externs carry and the def head is
correct. Not in the gate path (only o0_subsplit + jr_isolate_all import it).
This commit is contained in:
Drew T
2026-08-04 00:16:23 -06:00
parent 7a6a09379f
commit 356373efab
5 changed files with 52 additions and 10 deletions
+6 -6
View File
@@ -138,7 +138,7 @@
- **§3-The** — three-hypothesis trail, because two of them were wrong and the wrongness is instructive <sub>L6864</sub>
- **§129** — Post-carve, `rtu_match`/`match_one` COUNT THE JUMP TABLE AS INSTRUCTIONS; and a carve must never be committed without its owner (P30 S28, `func_8013BD74`) <sub>L8430</sub>
- **§129a** — the target instruction count is INFLATED after a carve <sub>L8434</sub>
- **§3-The** — DEFINITION-side alias is the only escape when the fleet canon disagrees on a promoting param <sub>L9455</sub>
- **§3-The** — DEFINITION-side alias is the only escape when the fleet canon disagrees on a promoting param <sub>L9463</sub>
### types, signedness & load/store width (29)
@@ -472,7 +472,7 @@
- **§3-The** — splitting/merging rules (each closed a residual, byte-gated) <sub>L8846</sub>
- **§137a** — A gate verdict has a TIMESTAMP; re-check it against the draft's mtime <sub>L9376</sub>
- **§138** — The propagation lanes: a gate refusal is a DECLARATION, and which lever you owe depends on blast radius <sub>L9405</sub>
- **§134** — again, in a second tool — and the waiter rule corrected <sub>L9472</sub>
- **§134** — again, in a second tool — and the waiter rule corrected <sub>L9480</sub>
### process, measurement & doctrine (53)
@@ -528,7 +528,7 @@
- **§136g** — When the index points at the WRONG lever: two byte-refuted routings (func_801863B4) <sub>L9201</sub>
- **§136h** — CORRECTION: the zero-crack pool does NOT "refill with cheap work" (my error, byte-measured) <sub>L9230</sub>
- **§136j** — The failure MIX flips with function size (measured across four bands, one session) <sub>L9292</sub>
- **Rank** — the lane by measured concentration, not by class count <sub>L9463</sub>
- **Rank** — the lane by measured concentration, not by class count <sub>L9471</sub>
### (unbucketed — title matched no symptom vocabulary) (108)
@@ -1028,6 +1028,6 @@
- **§137a** — A gate verdict has a TIMESTAMP; re-check it against the draft's mtime <sub>L9376</sub>
- **§138** — The propagation lanes: a gate refusal is a DECLARATION, and which lever you owe depends on blast radius <sub>L9405</sub>
- **§3-The** — triage, cheapest first <sub>L9411</sub>
- **§3-The** — DEFINITION-side alias is the only escape when the fleet canon disagrees on a promoting param <sub>L9455</sub>
- **Rank** — the lane by measured concentration, not by class count <sub>L9463</sub>
- **§134** — again, in a second tool — and the waiter rule corrected <sub>L9472</sub>
- **§3-The** — DEFINITION-side alias is the only escape when the fleet canon disagrees on a promoting param <sub>L9463</sub>
- **Rank** — the lane by measured concentration, not by class count <sub>L9471</sub>
- **§134** — again, in a second tool — and the waiter rule corrected <sub>L9480</sub>
+8
View File
@@ -9432,6 +9432,14 @@ bought 8 of 36 for one token.
says nothing about what is behind it (the S29 law). Fixing `func_8012E5CC` immediately revealed
`func_80147364` at the same site. Re-run after every fix; do not price the lane off the first error.
**Bucket by the (macro-shape, TU-shape) PAIR — NOT by the symbol.** The same symbol conflicts in
BOTH directions across the fleet, and the lever differs. `func_80146C3C` cost this lesson twice in
one session: in the EXTEND lane the macro said `(void)` and the TU `(u8*)`; in the PROPAGATE lane
the *mirror* — macro `(u8*)`, TU `(void)`. Relaxing only the `(void)` form (42 decls, byte-neutral,
R22-clean) fixed the first and did **nothing** for the second, which then banked 0/1 in all 134
overlays. One `awk` over the macro you are ACTUALLY fixing — not its sibling — shows the pair before
you spend a 134-build run. *Read the declaration of the macro in front of you.*
### `volatile` in the host TU is a SCHEDULING BARRIER — and it looks exactly like a codegen wall
The four "undiagnosed DIFF"s in `dedup_extend`'s own header were this. Its correctness argument says
+20
View File
@@ -207,6 +207,26 @@ is either a no-arg call or already cast ⇒ codegen-neutral.
an already-macro-ized group.** Probe: exactly **1** extendable group per ordinary overlay (so the
fleet has no hidden wiring backlog beyond this) ⇒ run it across the 134 non-SC07 overlays.
## ⚠️ MY WRONG PREDICTION, CORRECTED BY THE BYTES (R14/R37) — and it refines §138
Commit `commit:1382` relaxed 42 `extern void func_80146C3C(void);` decls and its message implies that
unblocked the PROPAGATE remainder. **It did not.** The re-run banked **0/1 in every one of the 134
overlays**, with the same error — because **`DEFINE_func_8016BA68` declares that symbol
`(u8*)`, not `(void)`**, and the TU declares it `(void)`. That is the **MIRROR** of the EXTEND-lane
pair, and my relax only touched one direction.
**Root cause (the R37 shape, again): I bucketed by SYMBOL and stopped there.** §138 says "bucket by
which symbol is named" — that is not sufficient. **The lever is determined by the (macro-shape,
TU-shape) PAIR**, and the same symbol conflicts in BOTH directions across the fleet:
· EXTEND lane: macro `(void)` vs TU `(u8*)` → relax the MACRO decl.
· PROPAGATE lane: macro `(u8*)` vs TU `(void)` → relax the MACRO decl *of the other form*.
One `awk` over the specific macro's own body — which I ran for the EXTEND macros and NOT for this
one — would have shown it before the 134-build run. **Read the decl of the macro you are actually
fixing, not of its sibling.**
The 42-decl relax is still **byte-neutral and still useful** (it removes a real conflict class and
R22 proved it 140/140) — it simply did not do the thing I predicted. Relaxing the remaining **2**
`(u8*)` decls is the actual fix for this lane. §138 to be amended with the PAIR rule.
## 🧹 THE §134 SCANNER SWEEP — sized, one clear target
Hand-rolled comment tests still outside the `cdecl._mask` oracle:
· **`tools/overlay_src_split.py:345`** (`_split_macro_body`) — **the IDENTICAL single-line-only
+2 -2
View File
@@ -429,7 +429,7 @@
#define DEFINE_func_8016BA68() \
extern s32 func_80146A6C(s32 a0, void *a1, s32 a2, s32 a3, s32 a4, s32 a5, s32 a6); \
extern s32 func_8014C050(s32 a0, s32 a1); \
extern void func_80146C3C(u8*); \
extern void func_80146C3C(); \
s32 func_8016BA68(s32 arg0, s32 arg1) { \
extern s32 D_80126B58; \
s32 temp_v0; \
@@ -30189,7 +30189,7 @@
#define DEFINE_func_8016BA68() \
extern s32 func_80146A6C(s32 a0, void *a1, s32 a2, s32 a3, s32 a4, s32 a5, s32 a6); \
extern s32 func_8014C050(s32 a0, s32 a1); \
extern void func_80146C3C(u8*); \
extern void func_80146C3C(); \
s32 func_8016BA68(s32 arg0, s32 arg1) { \
extern s32 D_80126B58; \
s32 temp_v0; \
+16 -2
View File
@@ -33,6 +33,8 @@ The whole-binary SHA1 byte-gate remains the sole correctness arbiter (G3/P9).
import os
import re
import sys
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import cdecl # the ONE comment/string masking oracle (Phase 26-A) — see _split_macro_body
REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@@ -338,11 +340,23 @@ _MACRO_TABLE = None
def _split_macro_body(body):
"""(leading_externs, def_lines) — a macro body's FILE-SCOPE extern lines (everything
before the definition header) and the definition itself."""
before the definition header) and the definition itself.
S33: the skip test used to be `startswith("//") or (startswith("/*") and endswith("*/"))`,
which sees a SINGLE-LINE comment and is blind to a MULTI-LINE block one — its opening line
does not end `*/` and its middle lines start `*`. The loop then treats that comment line as
the definition header and returns a TRUNCATED extern set. Measured at the time of the fix:
38 such lines live in engine_core.h macro bodies (the levers document themselves in block
comments). Same §134 class fixed in family_remap (S6b D1/D2/D5) and dedup_propagate.find_site
(S33). Decide on `cdecl._mask` — one oracle (R33), every comment form, immune to a `/*`
inside a string — with the length-preservation invariant asserted, not assumed (R32)."""
mbody = cdecl._mask("\n".join(body)).split("\n")
if len(mbody) != len(body):
mbody = body
out = []
for k, ln in enumerate(body):
s = ln.strip()
if not s or s.startswith("//") or (s.startswith("/*") and s.endswith("*/")):
if mbody[k].strip() == "":
continue
if s.startswith("extern"):
out.append(s)