From 2de4ef722a796cfc014cbb9fced1da530e5eb8bc Mon Sep 17 00:00:00 2001 From: Drew T <50529377+Druthulu@users.noreply.github.com> Date: Tue, 25 Aug 2026 02:06:20 -0600 Subject: [PATCH] =?UTF-8?q?feat(decomp):=20-O0=20U2=20=E2=80=94=20the=204?= =?UTF-8?q?=20SC07=20whale=20members=20bank,=204/4,=20zero=20model=20token?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rollout_o0 hardcoded `_o0b.c` as the whale object and listed SC07_006/007/010/011 as OUT-OF-SCOPE. They were never out of scope structurally — the suffix letter just drifts: _o0b across the fleet, _o0c in SC07_010, _o0d in SC07_006/007/011. The invariant that actually identifies the object is that it ENDS at the whale and therefore includes shared/func_80144B9C.h. whale_file_of() resolves on that content, and refuses (never guesses) when two -O0 files in one overlay match, or none do. NEGATIVE CONTROL (R39) over the already-succeeding population: across all 134 overlays that bank through the legacy `_o0b.c` path, content resolution returns EXACTLY that file — 134 agree, 0 disagree. The four SC07 overlays resolve to their _o0c/_o0d objects, and overlays with no -O0 object at all (ov_MAIN_012, ov_SC02_037, ov_SC03_107 — the U3 carve group) are still refused with `no-o0b`. Result: func_801457A4 BANKED in all four, each proven by `make build BINARY=` matching config/check..sha. 4 functions / 316 instructions, no splat change, no drafting. Also: build_ok() now takes `.run/auto/gate..lock`, the same per-binary lock the gater, sweep_parallel and the maintenance sweep take. This driver was written to be run by hand between waves; with six lanes live, two processes in one build/ tree would produce a verdict about neither. --- src/ov_SC07_006/ov_SC07_006_jr_801457A4.c | 4 +- src/ov_SC07_006/ov_SC07_006_o0d.c | 28 +++++++++++++ src/ov_SC07_007/ov_SC07_007_jr_801457A4.c | 4 +- src/ov_SC07_007/ov_SC07_007_o0d.c | 28 +++++++++++++ src/ov_SC07_010/ov_SC07_010_jr_801457A4.c | 4 +- src/ov_SC07_010/ov_SC07_010_o0c.c | 28 +++++++++++++ src/ov_SC07_011/ov_SC07_011_jr_801457A4.c | 4 +- src/ov_SC07_011/ov_SC07_011_o0d.c | 28 +++++++++++++ tools/rollout_o0.py | 51 ++++++++++++++++++----- 9 files changed, 161 insertions(+), 18 deletions(-) diff --git a/src/ov_SC07_006/ov_SC07_006_jr_801457A4.c b/src/ov_SC07_006/ov_SC07_006_jr_801457A4.c index 8c667b893..6191d73b2 100644 --- a/src/ov_SC07_006/ov_SC07_006_jr_801457A4.c +++ b/src/ov_SC07_006/ov_SC07_006_jr_801457A4.c @@ -1021,8 +1021,8 @@ extern unsigned short D_80126B66; extern int func_80144B14(int param_1); /* ==== end §8b carried decl layer ==== */ -INCLUDE_ASM("asm/ov_SC07_006/nonmatchings/ov_SC07_006_jr_801457A4", func_801457A4); - +/* func_801457A4 (@0x801457A4) is an -O0 function; its definition lives in ov_SC07_006_o0d.c (the -O0 + * whale object). Mirrors ov_SC01_077 (rollout_o0, generalizing §116/T85). */ void func_801458E0(void) { } diff --git a/src/ov_SC07_006/ov_SC07_006_o0d.c b/src/ov_SC07_006/ov_SC07_006_o0d.c index cd38f8c81..e7234b8b2 100644 --- a/src/ov_SC07_006/ov_SC07_006_o0d.c +++ b/src/ov_SC07_006/ov_SC07_006_o0d.c @@ -1012,3 +1012,31 @@ extern int func_80144B14(int param_1); #include "../shared/func_80144B9C.h" + + +/* func_801457A4 @ 0x801457A4 — an -O0 function stranded at the whale's end boundary (it is the + * FIRST fn of the -O2 "after" segment, but its target is -O0: frame-pointer + per-case stack + * reloads). It can only bank in an -O0 object, so it lives here: _o0b is already -O0-compiled and + * its .text ends exactly at 0x801457A4 (right after func_80144B9C), placing this fn at its true + * address with no linker/Makefile change. Its stub was removed from ov_SC01_077_after.c. Def sig + * conformed byte-neutrally to func_80144B9C.h's decl `void *func_801457A4(s32)` (the whale calls it + * that way); byte-proven at -O0 (match_one --o0 79/79) and by the whole-binary gate. Phase-29 bank. */ +extern int D_8018A3C0; + +void *func_801457A4(s32 param_1) { + switch (param_1) { + case 0x1010: + case 0x1052: + case 0x1077: + case 0x1094: + case 0x2013: + case 0x2015 ... 0x201a: + case 0x2055 ... 0x205b: + case 0x207a ... 0x2080: + case 0x2097 ... 0x209d: + return (void *)(&D_8018A3C0)[param_1 & 0xffff0fff]; + default: + return (void *)D_8018A3C0; + break; + } +} diff --git a/src/ov_SC07_007/ov_SC07_007_jr_801457A4.c b/src/ov_SC07_007/ov_SC07_007_jr_801457A4.c index dda9b19ba..d5367dc19 100644 --- a/src/ov_SC07_007/ov_SC07_007_jr_801457A4.c +++ b/src/ov_SC07_007/ov_SC07_007_jr_801457A4.c @@ -1017,8 +1017,8 @@ extern void func_80144AEC(s32 *a0); extern int func_80013294(void *a0, void *a1); /* ==== end §8b carried decl layer ==== */ -INCLUDE_ASM("asm/ov_SC07_007/nonmatchings/ov_SC07_007_jr_801457A4", func_801457A4); - +/* func_801457A4 (@0x801457A4) is an -O0 function; its definition lives in ov_SC07_007_o0d.c (the -O0 + * whale object). Mirrors ov_SC01_077 (rollout_o0, generalizing §116/T85). */ void func_801458E0(void) { } diff --git a/src/ov_SC07_007/ov_SC07_007_o0d.c b/src/ov_SC07_007/ov_SC07_007_o0d.c index 479b25d04..d0b2fb1b1 100644 --- a/src/ov_SC07_007/ov_SC07_007_o0d.c +++ b/src/ov_SC07_007/ov_SC07_007_o0d.c @@ -1007,3 +1007,31 @@ extern int func_80013294(void *a0, void *a1); #include "../shared/func_80144B9C.h" + + +/* func_801457A4 @ 0x801457A4 — an -O0 function stranded at the whale's end boundary (it is the + * FIRST fn of the -O2 "after" segment, but its target is -O0: frame-pointer + per-case stack + * reloads). It can only bank in an -O0 object, so it lives here: _o0b is already -O0-compiled and + * its .text ends exactly at 0x801457A4 (right after func_80144B9C), placing this fn at its true + * address with no linker/Makefile change. Its stub was removed from ov_SC01_077_after.c. Def sig + * conformed byte-neutrally to func_80144B9C.h's decl `void *func_801457A4(s32)` (the whale calls it + * that way); byte-proven at -O0 (match_one --o0 79/79) and by the whole-binary gate. Phase-29 bank. */ +extern int D_80182EE4; + +void *func_801457A4(s32 param_1) { + switch (param_1) { + case 0x1010: + case 0x1052: + case 0x1077: + case 0x1094: + case 0x2013: + case 0x2015 ... 0x201a: + case 0x2055 ... 0x205b: + case 0x207a ... 0x2080: + case 0x2097 ... 0x209d: + return (void *)(&D_80182EE4)[param_1 & 0xffff0fff]; + default: + return (void *)D_80182EE4; + break; + } +} diff --git a/src/ov_SC07_010/ov_SC07_010_jr_801457A4.c b/src/ov_SC07_010/ov_SC07_010_jr_801457A4.c index 0fe156830..bfffe9ad9 100644 --- a/src/ov_SC07_010/ov_SC07_010_jr_801457A4.c +++ b/src/ov_SC07_010/ov_SC07_010_jr_801457A4.c @@ -430,8 +430,8 @@ extern void func_80144AEC(s32 *a0); extern int func_80013294(void *a0, void *a1); /* ==== end §8b carried decl layer ==== */ -INCLUDE_ASM("asm/ov_SC07_010/nonmatchings/ov_SC07_010_jr_801457A4", func_801457A4); - +/* func_801457A4 (@0x801457A4) is an -O0 function; its definition lives in ov_SC07_010_o0c.c (the -O0 + * whale object). Mirrors ov_SC01_077 (rollout_o0, generalizing §116/T85). */ void func_801458E0(void) { } diff --git a/src/ov_SC07_010/ov_SC07_010_o0c.c b/src/ov_SC07_010/ov_SC07_010_o0c.c index faa007806..0a869d0d6 100644 --- a/src/ov_SC07_010/ov_SC07_010_o0c.c +++ b/src/ov_SC07_010/ov_SC07_010_o0c.c @@ -438,3 +438,31 @@ extern int func_80013294(void *a0, void *a1); #include "../shared/func_80144B9C.h" + + +/* func_801457A4 @ 0x801457A4 — an -O0 function stranded at the whale's end boundary (it is the + * FIRST fn of the -O2 "after" segment, but its target is -O0: frame-pointer + per-case stack + * reloads). It can only bank in an -O0 object, so it lives here: _o0b is already -O0-compiled and + * its .text ends exactly at 0x801457A4 (right after func_80144B9C), placing this fn at its true + * address with no linker/Makefile change. Its stub was removed from ov_SC01_077_after.c. Def sig + * conformed byte-neutrally to func_80144B9C.h's decl `void *func_801457A4(s32)` (the whale calls it + * that way); byte-proven at -O0 (match_one --o0 79/79) and by the whole-binary gate. Phase-29 bank. */ +extern int D_80181F74; + +void *func_801457A4(s32 param_1) { + switch (param_1) { + case 0x1010: + case 0x1052: + case 0x1077: + case 0x1094: + case 0x2013: + case 0x2015 ... 0x201a: + case 0x2055 ... 0x205b: + case 0x207a ... 0x2080: + case 0x2097 ... 0x209d: + return (void *)(&D_80181F74)[param_1 & 0xffff0fff]; + default: + return (void *)D_80181F74; + break; + } +} diff --git a/src/ov_SC07_011/ov_SC07_011_jr_801457A4.c b/src/ov_SC07_011/ov_SC07_011_jr_801457A4.c index bfb0ba29d..112bd4558 100644 --- a/src/ov_SC07_011/ov_SC07_011_jr_801457A4.c +++ b/src/ov_SC07_011/ov_SC07_011_jr_801457A4.c @@ -1018,8 +1018,8 @@ extern void func_80144AEC(s32 *a0); extern int func_80013294(void *a0, void *a1); /* ==== end §8b carried decl layer ==== */ -INCLUDE_ASM("asm/ov_SC07_011/nonmatchings/ov_SC07_011_jr_801457A4", func_801457A4); - +/* func_801457A4 (@0x801457A4) is an -O0 function; its definition lives in ov_SC07_011_o0d.c (the -O0 + * whale object). Mirrors ov_SC01_077 (rollout_o0, generalizing §116/T85). */ void func_801458E0(void) { } diff --git a/src/ov_SC07_011/ov_SC07_011_o0d.c b/src/ov_SC07_011/ov_SC07_011_o0d.c index 9a1a58a9c..320c0f207 100644 --- a/src/ov_SC07_011/ov_SC07_011_o0d.c +++ b/src/ov_SC07_011/ov_SC07_011_o0d.c @@ -1008,3 +1008,31 @@ extern int func_80013294(void *a0, void *a1); #include "../shared/func_80144B9C.h" + + +/* func_801457A4 @ 0x801457A4 — an -O0 function stranded at the whale's end boundary (it is the + * FIRST fn of the -O2 "after" segment, but its target is -O0: frame-pointer + per-case stack + * reloads). It can only bank in an -O0 object, so it lives here: _o0b is already -O0-compiled and + * its .text ends exactly at 0x801457A4 (right after func_80144B9C), placing this fn at its true + * address with no linker/Makefile change. Its stub was removed from ov_SC01_077_after.c. Def sig + * conformed byte-neutrally to func_80144B9C.h's decl `void *func_801457A4(s32)` (the whale calls it + * that way); byte-proven at -O0 (match_one --o0 79/79) and by the whole-binary gate. Phase-29 bank. */ +extern int D_8017E634; + +void *func_801457A4(s32 param_1) { + switch (param_1) { + case 0x1010: + case 0x1052: + case 0x1077: + case 0x1094: + case 0x2013: + case 0x2015 ... 0x201a: + case 0x2055 ... 0x205b: + case 0x207a ... 0x2080: + case 0x2097 ... 0x209d: + return (void *)(&D_8017E634)[param_1 & 0xffff0fff]; + default: + return (void *)D_8017E634; + break; + } +} diff --git a/tools/rollout_o0.py b/tools/rollout_o0.py index f89d65203..b250e535b 100644 --- a/tools/rollout_o0.py +++ b/tools/rollout_o0.py @@ -22,7 +22,12 @@ Scope rules (R14/§52b — every claim gated, nothing forced): * members come from the family map (handles cross-address families: the stub NAME is derived from the MEMBER's address, not the exemplar's); each member's stub line is located in any of its overlay's non-`_o0` TUs (T85 hardcoded `_after.c`; SC05_017's stub lives elsewhere). - * overlays without `_o0b.c` (the 4 SC07) are reported OUT-OF-SCOPE, never guessed at. + * the whale object is resolved BY CONTENT, not by name (P31 S60/U2). The letter drifts across + the fleet — `_o0b` almost everywhere, `_o0c` in ov_SC07_010, `_o0d` in SC07_006/007/011 — and + hardcoding `_o0b.c` put four overlays permanently OUT-OF-SCOPE for a naming reason, not a + structural one. The invariant that actually identifies the file is that it ENDS at the whale + and therefore includes `shared/func_80144B9C.h`; resolve on that and the four join the fleet + with no splat change and no new mechanics. An overlay with no such file is still refused. * the driver does NOT commit; the operator commits per family after the batch's R22 clean-fleet. tools/rollout_o0.py --fn func_8013B6A0 [--apply] [--limit N] [--jobs N] @@ -44,7 +49,7 @@ sys.path.insert(0, os.path.join(REPO, "tools")) import family_remap as FR # noqa: E402 EX_OV = "ov_SC01_077" -SC07_NO_O0B = {"ov_SC07_006", "ov_SC07_007", "ov_SC07_010", "ov_SC07_011"} +WHALE_HDR = "shared/func_80144B9C.h" NOTE = ("/* {fn} (@0x{addr:08X}) is an -O0 function; its definition lives in {o0b} (the -O0\n" " * whale object). Mirrors ov_SC01_077 (rollout_o0, generalizing §116/T85). */") @@ -63,10 +68,21 @@ def good_sha(ov): def build_ok(ov): - r = subprocess.run(["make", "build", f"BINARY={ov}"], cwd=REPO, - stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - out = os.path.join(REPO, f"build/{ov}/{ov}") - return r.returncode == 0 and os.path.exists(out) and sha1(out) == good_sha(ov) + """Build ONE overlay under the SAME per-binary lock every other gate takes. + + Without it this driver raced the campaign lanes: the gater, sweep_parallel and the + maintenance sweep all build binaries concurrently under `.run/auto/gate..lock`, and two + processes in one `build/` tree produce a verdict about neither tree. The driver used to + be run by hand between waves, so the gap never fired; with six lanes running it would. + """ + lock_path = os.path.join(REPO, f".run/auto/gate.{ov}.lock") + with open(lock_path, "w") as lk: + import fcntl + fcntl.flock(lk, fcntl.LOCK_EX) + r = subprocess.run(["make", "build", f"BINARY={ov}"], cwd=REPO, + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + out = os.path.join(REPO, f"build/{ov}/{ov}") + return r.returncode == 0 and os.path.exists(out) and sha1(out) == good_sha(ov) def o0_matched_exemplars(): @@ -94,12 +110,27 @@ def stub_file_of(ov, fn): return None, pat +def whale_file_of(ov): + """The overlay's -O0 object that ENDS at the whale (0x801457A4), found by content. + + One file per overlay includes the whale's shared header; that include is the structural + identity of the object, while the `_o0` suffix is an artefact of how many carves that + overlay happened to need. Refuses on ambiguity rather than picking one (R43): two matches means + the assumption behind the append is wrong for this overlay and a human should look. + """ + hits = [p for p in sorted(glob.glob(os.path.join(REPO, f"src/{ov}/{ov}_o0*.c"))) + if WHALE_HDR in open(p, errors="replace").read()] + if len(hits) > 1: + print(f" {ov}: REFUSED — {len(hits)} -O0 files include the whale header: " + f"{[os.path.basename(h) for h in hits]}", flush=True) + return None + return hits[0] if hits else None + + def attempt(ex_addr, ov, member_addr, apply): fn = "func_%08X" % member_addr - if ov in SC07_NO_O0B: - return ov, "out-of-scope-sc07", "" - o0b = os.path.join(REPO, f"src/{ov}/{ov}_o0b.c") - if not os.path.exists(o0b): + o0b = whale_file_of(ov) + if not o0b: return ov, "no-o0b", "" stub_path, pat = stub_file_of(ov, fn) if not stub_path: