From 356373efabb08b6470aad01ea43951a69b09ac79 Mon Sep 17 00:00:00 2001 From: Drew T <50529377+Druthulu@users.noreply.github.com> Date: Tue, 4 Aug 2026 00:16:23 -0600 Subject: [PATCH] =?UTF-8?q?fix(phase-30=20S33b):=20the=20PAIR=20rule=20?= =?UTF-8?q?=E2=80=94=20my=2042-decl=20relax=20did=20NOT=20unblock=20the=20?= =?UTF-8?q?lane;=20the=20mirror=20form=20did?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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). --- docs/cookbook-index.md | 12 ++++++------ docs/matching-cookbook.md | 8 ++++++++ phase-ends/CURRENT_PHASE.md | 20 ++++++++++++++++++++ src/shared/engine_core.h | 4 ++-- tools/overlay_src_split.py | 18 ++++++++++++++++-- 5 files changed, 52 insertions(+), 10 deletions(-) diff --git a/docs/cookbook-index.md b/docs/cookbook-index.md index 4906ba081..f7ac78b4d 100644 --- a/docs/cookbook-index.md +++ b/docs/cookbook-index.md @@ -138,7 +138,7 @@ - **§3-The** — three-hypothesis trail, because two of them were wrong and the wrongness is instructive L6864 - **§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`) L8430 - **§129a** — the target instruction count is INFLATED after a carve L8434 -- **§3-The** — DEFINITION-side alias is the only escape when the fleet canon disagrees on a promoting param L9455 +- **§3-The** — DEFINITION-side alias is the only escape when the fleet canon disagrees on a promoting param L9463 ### types, signedness & load/store width (29) @@ -472,7 +472,7 @@ - **§3-The** — splitting/merging rules (each closed a residual, byte-gated) L8846 - **§137a** — A gate verdict has a TIMESTAMP; re-check it against the draft's mtime L9376 - **§138** — The propagation lanes: a gate refusal is a DECLARATION, and which lever you owe depends on blast radius L9405 -- **§134** — again, in a second tool — and the waiter rule corrected L9472 +- **§134** — again, in a second tool — and the waiter rule corrected L9480 ### process, measurement & doctrine (53) @@ -528,7 +528,7 @@ - **§136g** — When the index points at the WRONG lever: two byte-refuted routings (func_801863B4) L9201 - **§136h** — CORRECTION: the zero-crack pool does NOT "refill with cheap work" (my error, byte-measured) L9230 - **§136j** — The failure MIX flips with function size (measured across four bands, one session) L9292 -- **Rank** — the lane by measured concentration, not by class count L9463 +- **Rank** — the lane by measured concentration, not by class count L9471 ### (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 L9376 - **§138** — The propagation lanes: a gate refusal is a DECLARATION, and which lever you owe depends on blast radius L9405 - **§3-The** — triage, cheapest first L9411 -- **§3-The** — DEFINITION-side alias is the only escape when the fleet canon disagrees on a promoting param L9455 -- **Rank** — the lane by measured concentration, not by class count L9463 -- **§134** — again, in a second tool — and the waiter rule corrected L9472 +- **§3-The** — DEFINITION-side alias is the only escape when the fleet canon disagrees on a promoting param L9463 +- **Rank** — the lane by measured concentration, not by class count L9471 +- **§134** — again, in a second tool — and the waiter rule corrected L9480 diff --git a/docs/matching-cookbook.md b/docs/matching-cookbook.md index e4f83637c..2bf15002a 100644 --- a/docs/matching-cookbook.md +++ b/docs/matching-cookbook.md @@ -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 diff --git a/phase-ends/CURRENT_PHASE.md b/phase-ends/CURRENT_PHASE.md index 7009df1ac..08e36e06e 100644 --- a/phase-ends/CURRENT_PHASE.md +++ b/phase-ends/CURRENT_PHASE.md @@ -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 diff --git a/src/shared/engine_core.h b/src/shared/engine_core.h index 2d2160050..eed55adcc 100644 --- a/src/shared/engine_core.h +++ b/src/shared/engine_core.h @@ -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; \ diff --git a/tools/overlay_src_split.py b/tools/overlay_src_split.py index 29c7e70c4..dbb263f7a 100644 --- a/tools/overlay_src_split.py +++ b/tools/overlay_src_split.py @@ -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)