main's gate could only ever say "got X want Y". S71 read 7 such verdicts as body
rejects and recorded 11 functions as "PROVEN gate-rejects, §376 in its purest form".
They are not: all 11 are switch functions, and the blocker is that main has had
exactly ONE rodata carve since Phase 7 (LZSS's jtbl_80072A38). Every other main jump
table stayed raw in the tail data, so a drafted switch DOUBLE-EMITTED its table, the
image grew (+28/+52/+76/+84 measured), and all 238 symbols above 0x80072A4C shifted.
* tools/main_diff_locate.py (NEW) — turns a red image into a named list of divergent
symbols via the linker map; per-byte attribution, self-test flips a byte at a known
address and asserts the containing symbol (plus the identical-pair direction).
* gate_main.py — PRESERVES the red image + map before the R40 baseline control
rebuilds over it, and auto-localizes: BODY REJECT vs PLUMBING REJECT vs MIXED. Also
-j on the build (was single-threaded) and the §376 drop list written to
.run/gate_main_dropped.json with the reconciliation chain.
* splat.us.exe.yaml — the .rodata carve extends from the LZSS table alone to the whole
contiguous game-jtbl span 0x80072A38-0x80072C70 (12 tables, one 800.o run).
Byte-neutral with no drafts substituted (probed first).
* jtbl_rodata_pads.py — --derive now works for main: one file-0-vram expression makes
both address->bytes and yaml-piece->address correct for the EXE's 0x800 header and
leaves flat overlays unchanged. Makefile arms it for BINARY=main.
Banked byte-identical: func_8001A114, func_8001AAD0, func_8001AF34 — three of the
eleven. 25 of main's 59 frontier functions (6,215 of 12,912 instructions) are in this
class; the remaining spans need src/800.c split at the TU boundaries the spans reveal.
A §332 delay-slot wall the pinned triple cannot emit from C; banked the verbatim-asm way,
verified by one clean rebuild at 143dbb89f34491258bbc27810d0a12ec8b43a8dd. Bank confirmed
from the source (stub gone), not from the tool's own count.
The main lane, run the ONLY way main can be gated (§414): substitute the whole slate ->
make extract -> make build -> compare SHA1, with a bisect when the batch fails.
Baseline asserted green first (143dbb89...), batch of 6 failed, bisect isolated
func_8002C410 in 7 rebuilds, and the remaining 5 banked BYTE-IDENTICAL.
Four of the five are §265 verbatim-asm bodies for functions on the §332/§188 toolchain
wall list - the accepted route for a function the pinned triple cannot emit from C, the
same way func_800D0B1C banked overnight. Candidates came from scoring every stored draft
for main's 53 non-rejected open functions with match_one: 6 of 53 at closeness 0.
The R22 clean-fleet verify came back 212/213. The failure is main, and `git log -L` puts
all four conflicting declaration lines in commit:3586 — this session's own main re-gate:
src/800.c:24519 extern int func_8004355C(s32, void *); vs :24396 (s32, u8 *)
src/800.c:26395 extern void func_80038FFC(); vs the s32 definition below
Reconciling both declarations (byte-neutral, §376) made main COMPILE, and it was then
still not byte-identical — so the commit was wrong on both counts, not merely unbuildable.
The gate reported "11 banked" against a tree that cannot compile from clean.
src/800.c restored to commit:3586^; `make extract BINARY=main && make build BINARY=main`
now gives sha1 143dbb89f34491258bbc27810d0a12ec8b43a8dd BYTE-IDENTICAL. The 11 bodies are
kept at .run/S71_main_suspect/800.c.banked11 for a per-function re-gate — this revert is
about restoring a green fleet, not a verdict on every one of them.
The type-name scan matched `}\s*(\w+)\s*;`, which reads `__attribute__` as the name
and fails on the following `((` — so a packed file-local typedef never entered the
carried set, every decl naming it read as an unknown type, and the isolate refused the
whole overlay. Stripping attributes before the scan is the entire fix.
The type-name scan matched `}\s*(\w+)\s*;`, which reads `__attribute__` as the name
and fails on the following `((` — so a packed file-local typedef never entered the
carried set, every decl naming it read as an unknown type, and the isolate refused the
whole overlay. Stripping attributes before the scan is the entire fix.
The CARVE-REFUSED class (10 of the frontier's gate failures) has one dominant cause:
"subseg <ov>_jr_<addr> would host NON-CONTIGUOUS .rodata carves", whose named remedy
is jr_isolate_all. The isolate itself then refused 4 of the 6 affected overlays over a
file-local `static inline` helper (bandsetup, setup_80188D90) that has no address BY
CONSTRUCTION — §82.1 helpers exist to shape their caller's code and emit no symbol.
* jr_isolate_all now places such a definition with the ONE region that uses it, and
refuses loudly if two regions do (two copies of a used static is a byte change, R43).
* overlay_src_split._proto_from_lines no longer prefixes `extern` to a declaration that
already has a storage class — `extern static inline void f(...)` is "multiple storage
classes" to cc1. The two changes are inseparable: placing statics is what first made
the tool emit a prototype for one.
Byte-gated on ov_SC03_010: extract + build rc=0,
sha1 cacaf7c2c08037e6934f9d02c0ae5d7c78cf2463 BYTE-IDENTICAL. jtbl_carve --probe then
moves from `plan-refused` to `tail — standard §8a carve at gate time`.
`migrated_tables()` can flag a function whose table is actually in the DATA TAIL,
and the §154-A island branch then refused the whole batch with "a tail carve cannot
help ... the carve model covers jump tables only, not an island of mixed included
data". That reads as a permanent toolchain wall. It is a ROUTING error: island_probe
classifies the same function 'tail', and its own detail says "standard §8a carve at
gate time" -- i.e. it names the ordinary lane as the owner (R43: each probe kind
names the lane that owns it). The refusal was about the branch we entered, not the
function.
Consult the probe first and let a 'tail' function fall through to build_carve.
Byte-proven immediately: ov_SC02_000/func_8017F950 -- three full parallel_gate
passes had booked it CARVE-REFUSED -- now reports `[jtbl] carved func_8017F950`,
`verified 1 / failed 0`, BYTE-IDENTICAL, and corpus.stubs confirms it banked. No
config change was needed: its carve was already committed and merely PENDING an
owner (the class identified while fixing jr_inventory), so banking the function
completed the 1:1 ownership the assertion wanted.
This was blocker 3 of 3 on the §322b route; 1 and 2 were cleared earlier in S70.
`parallel_gate` commits with `git add -u src/`, which updates TRACKED files and
cannot add NEW ones. A jtbl carve SPLITS a TU, creating `src/<bin>/<bin>_jr_<addr>.c`
— so every carve landed its yaml change (tracked) while leaving the new source
file UNTRACKED.
Why this mattered: `config/splat.<bin>.yaml` is committed and names the subseg
(`- [0x577f8, c, ov_SC02_000_jr_8017F950]`), and 31 sibling `_jr_` files in that
same binary are tracked — so these are source by convention, not build artifacts.
R22 passed locally only because they exist on disk. A fresh clone, or Drew's
push, would have the yaml without the file.
Found because parallel_gate REFUSED to run with an unclean tree (rc=1) and listed
them — the guard did its job; the earlier `REFUSED 8 (main tree moved under them)`
line in the carve gate was the same eight files.
TODO for the tool: parallel_gate's commit step must add NEW files under
src/<binary>/ that its own carve produced (narrowly, per-binary — never a blanket
`git add src/`, per the carve-state discipline).