Worked Drew's order 1->2->3->4 at xHigh (no fan-out).
ITEM 1 func_80176734: permuter COMPLETELY FLAT at 13 (8 cycles x 240s, regalloc profile chosen over
the classifier's cse because the residual is 3 register 2-swaps). Not one improving waypoint in 32
min. THIRD ADDRESSING-bucketed target in a row where the permuter under-delivers (11->7, 10->6,
now 13->13 flat) — the T31 routing finding is now well evidenced. Remaining: the reg_renumber-swap
gdb oracle; feasibility confirmed (cc1 unstripped, reg_renumber @0x82d4330, prior-art .gdb exists)
but it needs a .greg pseudo-identification pass, so not started.
ITEM 2: 4 of 7 banked — func_80177DA8, func_8013B6A0, func_8013B598, func_80138C60. THE BARE GATE
WAS THE UNLOCK: gate_stage reported failed:2 on the _o0 pair while bare harvest_verify reported
verified 2/failed 0 on the SAME drafts, and rtu_match independently confirms func_8013B6A0 matches
in the real TU. That gives the carried "ladder-vs-bare-gate asymmetry" defect a REPRODUCTION — the
ladder is destroying good drafts, not diagnosing them. All 4 are reach-138 PURE families =
35,604 templatable instructions.
SHARED-STATE HAZARD hit and repaired: the failed func_80135260 attempt left fix_arity_callers
--any-proto edits in 17 TUs holding none of my banks (the bare gate has no snapshot/restore, unlike
the ladder after the Task-14 incident). Caught by diffing the tree, not by the tool's report.
Reverted the 17, kept the 3 bank-bearing files, re-verified R22 clean-fleet 140/140. Nothing under
src/shared, config or include was touched, so blast radius was ov_SC01_077-local (§63).
ITEM 3 func_80140D68: fails even bare-gated, and the PREDICTED CAUSE WAS WRONG — there is no
DEFINE_func_80140D68 macro. Real conflict is §99 K&R-vs-prototype: draft is K&R `u32 *`, 138 callers
declare `extern s32 *func_80140D68(s32 *, Prim4 *, s32, s32, s32);`. Lever exists (§99 did this at
1,072-decl scale today) but it is a fleet-shared 138-decl change. Scoped, not attempted.
ITEM 4 func_80178004 biv-init wall: RE-PROBED and UPHELD — my own hypothesis refuted. The cited
mechanism (loop.c:3803/3823, benefit->0 eliminates emit_iv_add_mult) is verbatim present in real
2.7.2 inside strength_reduce (3214); loop.md's flagged version difference is in combine_givs, which
this verdict does not rest on. The wall stands.
- family_sweep --hseq --band all --only <4 cores> -j12 -> BANKED 548 member-matches / 0 failed
across 137 overlays. Preconditions CHECKED not assumed: map regenerated first (sig-overlays +
family_hseq) so the exemplars read matched-ov077 not the stale draft-ov077; all 4 families
has_mid_jr=false (§53 carve law) and diff_class PURE 137/137; --band all because two cores are
`mid` and the default `substantial` band would have silently dropped them; --reconcile-raw avoided.
- R22 clean-fleet after the sweep: 140 passed, 0 failed of 140. dedup-check 1886 validated / 0
failed, C1 coverage 239604/239604, 0 NON_MATCHING in any default build (G4).
- SESSION ARC: instr 84.8 -> 85.3%, distinct-code 74.7 -> 75.8%, fn-count 90.34 -> 90.50%.
552 functions banked (4 exemplars + 548 members) ~= 74,802 templated instructions.
- sched.md SOURCE-VERSION CORRECTION: the map declares its source as gcc-papermario, which Phase 23
established is gcc 2.8.1 — not our 2.7.2 — and it was never re-derived. Citations are correct for
the WRONG compiler. One claim is byte-refuted and load-bearing: §1.7/§S12 said the S2 birthing
boost needs SET(REG_pseudo,...) so pins must be removed ("Unpin first"); real 2.7.2
birthing_insn_p (sched.c:2469) tests only GET_CODE(SET_DEST)==REG with NO pseudo check and gates on
reg_n_sets==1 (2490) — hard-reg dests ARE boosted. Corrected in place (old text struck, not
deleted) + a hand-verified 2.7.2 cross-reference table and a warning block.
DRIFT IS NOT UNIFORM: ~+27 in sched.c but +103/+377/+611 in local-alloc.c/reload1.c — big enough to
land inside a different function. ~44 drifted citations across sched/regalloc/loop .md (a screen,
a lower bound). regalloc.md is worst and is NOT yet re-derived — named as next.
- All line numbers verified by me against tools/reference/gcc-2.7.2, not taken from the agents.
Ultracode fan-out (12 agents, 1.70M subagent tokens): 6 crack agents, one per NEAR target, each
carrying its byte-measured residual + T31's disproved routes, then a distill agent per target that
adversarially re-checks the claim.
- BANKED ×1 (whole-binary gate, gate_stage --no-propagate per §55b law 1): func_80140958 (260 ins),
func_80177B5C (147), func_80132F40 (72), func_8012E364 (67). Every agent MATCH claim was
RE-MEASURED BY ME with match_one before it was believed (G3/P9: match_one is a candidate, a bank
is the whole-binary gate), and verified against the SOURCE not gate_stage's accumulating
verified-list (§55b trap 4). R22 clean-fleet: 140 passed, 0 failed of 140.
- engine_core.h moved by exactly one byte-neutral arity fix (void -> no-proto) = fleet-shared, so
R22 was mandatory (§61/§63), not the per-binary gate.
- func_80140D68 MATCHes standalone but NOT whole-binary — the §30a integration class; its distill
agent named the likely cause in advance (DEFINE_func_* extern must return u32*, not void).
- func_80176734 217 -> 13 with the instruction count now EXACT (371/371). cse_expr.md §H's "no bank,
5 permuter-shaped clusters" is BYTE-REFUTED: 4 of 5 were steerable from C; the -1 length delta was
a combine/LOG_LINK effect (flow.c links a SET only to the next use in the SAME bb), not frame
pressure. Two coupled allocator/sched ties survive.
- FOUND: docs/gcc-2.7.2-map/sched.md cites gcc-2.8.1 line numbers (birthing_insn_p 2498->2469,
adjust_priority 2534->2507, potential_hazard 1345->1318, schedule_select 2646->2616) — surviving
papermario numbers Phase 23's source-version correction never swept. One is LOAD-BEARING: §1.7 and
§S12 claim the S2 boost needs SET(REG_pseudo,...) so pins must be removed; sched.c:2477 tests only
GET_CODE(SET_DEST)==REG with NO pseudo check, discriminator is reg_n_sets==1 (2490). Verified by me
against tools/reference/gcc-2.7.2, not taken from the agents. Map edits owed (next task).
- MY DEFECT: all 6 agents shared one scratch dir (1,452 files); deliverables are uniquely named and
verified intact, but short-named scratch could collide. Per-agent subdirs next wave.
137/137 banked via jtbl_family_bank (jr family, carve-aware path). R22 clean-fleet 140 passed /
0 failed of 140. MEASURED: fn-count 319,412 -> 319,549 (+137); instr-weighted 84.7 -> 84.8%
(+9,590 ins); distinct-code 74.5 -> 74.7% (+130 unique fns).
WAVE22 COMPLETE: 18 targets drafted (12 MATCH / 6 NEAR / 0 FAIL, 2.59M subagent tokens) ->
5 exemplars banked -> 685 members swept -> 690 functions total.
This commit stages config/ EXPLICITLY. Twice today I omitted it and left a carve uncommitted, both
times caught by jtbl_family_bank's dirty-tree precondition rather than by me or any gate.
4 families x 137 members: BANKED 548 / 0 failed. R22 clean-fleet 140 passed / 0 failed of 140.
MEASURED: fn-count 318,859 -> 319,412 (+553); instr-weighted 84.4 -> 84.7% (+36,640 ins);
distinct-code 74.4 -> 74.5% (+134 unique fns).
TODAY'S PARALLEL GATE WIRING PROVED AT SCALE: this run reported `gating 411 group(s) across distinct
binaries, -j12`. When I shipped it earlier I could only smoke-test 4 fail-fast groups and said
explicitly that the 1.5x measured there was NOT the 8-16x claim; 411 full build-and-gate cycles is
the shape the claim was about.
A PERFECT 548/548 also says the wave's exemplars were right for the right reasons — a body that
templates across 137 byte-variant siblings with zero rejections is not a marginal match.
BAND NOTE: the first sweep attempt used --band substantial and staged NOTHING; these exemplars are
60-76 ins, i.e. the MID band (substantial is >=80). The tool reported that honestly
("0 matched-exemplar families (band=substantial); 0 candidate members") rather than returning a
clean-looking 0 banked — the skip-vs-result distinction this session kept running into.
THE WAVE: 18 h_seq family exemplars (~255k templated instructions), one agent each, drafting from
cached Ghidra-C + the target .s with canonical callee/data decls resolved from the real TU scope.
Result 12 MATCH / 6 NEAR / 0 FAIL (2.59M subagent tokens). No agent touched the tree — the
draft-only constraint held (verified: git status clean across src/config/tools/include).
BANKED 5: func_80148E54, func_80171B4C, func_8014A738, func_8012A328, func_80163534.
R22 clean-fleet 140 passed / 0 failed of 140.
A BUG I INTRODUCED EARLIER TODAY, FOUND BY WORKING THE 12->5 GAP. My block-scope descent in
reconcile_tu fed ordinary STATEMENTS to cdecl.parse; some parse without raising into a declarator
with an EMPTY base type and the statement's symbol as its name. That fake row overwrote the genuine
plan entry for the same symbol, so the span rewrite landed on a statement instead of the declaration
— and my own R32 completion assertion still PASSED, because the conformed text appeared somewhere.
Byte-witnessed on D_80126B5C: planned twice ("draft 's32'" and "draft ''"), output unchanged, gate
PLUMBING. Now block-scope rows are accepted only from a real `extern` with a non-empty base type.
TWO BANKS CAME FROM TODAY'S OWN FINDINGS:
- func_8012E014's single 0-arg call site took --cast-zero-arg-calls (built this morning for
func_801789AC's 138 sites).
- §99 HELD A THIRD TIME: K&R conversion dissolved func_80163534's s32->u16 narrowing across 1,072
declarations, leaving only a caller-neutral pointer change on the last param.
STILL UNBANKED (measured blockers, not guesses): func_8013B6A0 + func_8013B598 CC1-FAIL in the _o0
split; func_80133298 + func_80135260 + func_8012E014 genuine DIFF (match_one MATCH did not hold
whole-binary = TU-context); func_80138C60 parse-order (an extern referencing a body-local typedef
declared after it); func_80177DA8 prototype-vs-K&R mismatch.
Its 0/137 was the §94 TYPE-CARRY signature: the draft defines `typedef struct {…} Sp_80175DA8;` at
FILE scope, and remap_hseq templates the BODY but not the type, so every sibling compiled without it.
§94's remedy is the shared engine_types.h lift (right for func_8016B6BC, whose four types were
transitively referenced). But the cheap remedy was already in the same draft: it carries S_AF634 at
BLOCK scope and that templates fine, because a type declared in the body travels WITH the body.
Sp_80175DA8 is used by that function ONLY (7 mentions, 6 inside the body, 0 elsewhere), so moving it
into the body is byte-neutral (d19c9580 unchanged), T0, zero blast radius — versus editing a header
included by 140 binaries with uniquify/collision care and an R22.
Re-swept: 137/137, 0 failed. R22 clean-fleet 140 passed / 0 failed of 140.
MEASURED: fn-count 318,720 -> 318,857 (+137); instr 84.2 -> 84.4% (+31,647 ins); distinct-code
73.9 -> 74.4% (+129 unique fns).
§99 AND §100, AN HOUR APART, ARE THE SAME LESSON: both times the cookbook's named remedy was the
expensive fleet-wide one (524-site decl conform / shared-header lift) and the correct fix was
DRAFT-LOCAL (K&R definition / block-scope typedef). Before editing anything shared, ask what the
smallest scope is that still travels with the body.
The first sweep returned "banked 0 / skipped {'pinned-exemplar': 137}" — a SKIP, not a failure. The
§42e guard refuses pinned exemplars to avoid a cc1 SIGABRT, but Phase 27 BYTE-PROVED that crash was
extract_unit dropping file-scope macros (a TOOL bug, fixed by _carry_macros), not a compiler limit.
Re-run with --allow-pins: 133/137 BANKED. R22 clean-fleet 140 passed / 0 failed of 140.
MEASURED: fn-count 318,585 -> 318,720 (+135); instr 84.0 -> 84.2% (+25,423 ins); distinct-code
73.4 -> 73.9% (+127 unique fns).
THE GUARD IS NOW COSTING BANKS — the same shape as sweep_parallel being opt-in: a protection that was
correct when written, whose cause was later removed, still defaults ON. Measured cost on ONE family:
137 skipped, 133 bank fine. Phase 27's roadmap delta already said the PINS class was back on the
table; nothing changed the default. Flipping it is a one-line change, deliberately deferred to a
fresh session — that is exactly how family_sweep got broken twice today.
SC07 QUARTET, third occurrence today, now named: ov_SC07_006/007/010/011 refused again (same four as
func_80176218). NOT broken — func_8014CF04, func_8015D1B8 and func_801789AC all swept them cleanly.
The correlation is the sibling TU (_jr_8016AE5C.c, a different carve layout; these 4 were onboarded
in Phase 27 with code at PAC entry 1). §59: read ONE sibling's real gate result before concluding.
func_80175DA8 0/137 is the §94 TYPE-CARRY signature (local typedef Sp_80175DA8 templated as a body
but not as a type) — the same shape that took func_8016B6BC 0/137 -> 137/137 today. Named next step,
31,878 templated instructions.
func_80175AB8 + func_80175DA8 both banked. R22 clean-fleet 140 passed / 0 failed of 140.
§92 SAID these need "the §17a-1 caller pair, NOT a bare conform" — the diagnosis was right (conforming
a narrow param changes argument promotion at every call site, measured PLUMBING -> DIFF) but the
remedy was the expensive one. The actual fix touches NO declaration: convert the DEFINITION to K&R,
where a narrow param PROMOTES to int (C89 6.3.2.2) and is therefore already compatible with the
fleet's existing `s32` prototype, while still emitting narrow-param codegen. §43 applied to the def
side. T0 draft-only, ZERO blast radius, versus a 524-site fleet conform.
THREE reconcile_tu BUGS SURFACED, ONE OF THEM MINE:
(a) BLIND TO BLOCK SCOPE. split_statements is depth-0 BY DESIGN, and §8d deliberately demotes data
externs into the function body — so the tool saw one statement and no declarations, printing
"reconciled: 0 draft(s), 0 data symbol(s); coverage defects: 0" for a draft cc1 rejected with
`conflicting types for D_8011F7BC`. A silent skip (R32). Fixed: descend one level.
(b) MY BUG, introduced by (a): descending into ANY `{` also enters struct/union/enum definitions, so
MEMBERS parse as declarations and get conformed — `u32 code;` became the TU's
`typedef void (*code)(unsigned short*);` INSIDE the struct, and `p->code` became
`p->(*(u32 *)&code)`. Caught by DIFFING THE TOOL'S OUTPUT AGAINST ITS INPUT before trusting it;
the byte-gate would have said PLUMBING and explained nothing. Guard: function bodies only.
(c) LATENT since the tool was written: _cast_sub matched bare identifiers and rewrote MEMBER ACCESSES
as globals. Unreachable until (a) existed. Guard: (?<![.\w])(?<!->).
cookbook §99.
137/137 banked, 0 failed via jtbl_family_bank. R22 clean-fleet 140 passed / 0 failed of 140; report
fail-closed green (dedup 1886/0, C1 coverage 239604/239604, 0 NON_MATCHING).
MEASURED: fn-count 318,447 -> 318,585 (+138); instr-weighted 83.9 -> 84.0% (+12,558 ins);
distinct-code 73.2 -> 73.4% (+131 unique fns — byte-VARIANT members, so unlike func_801330E0's
byte-identical family this one moves the distinct number too).
Closes the function REFUSED since SESSION-21 — correctly refused, since conforming its 660
declarations without first casting its 138 zero-arg call sites would have broken 138 binaries.
Also logged (T21): the sweep-throughput measurement. Drew was right that parallelism was proven and
adopted (Makefile JOBS=16; sweep_parallel.py -j12 built SESSION-20 after measuring an 8-16x loss),
but NEITHER sweep tool calls it — the adapter is reachable only via a manual --stage-only two-step,
so three sweeps today ran serially for no reason. The -j theory was wrong and measurement said so:
make is ~5s of the 16s per sibling (the loop runs up to FOUR builds per sibling), so -j16 is a 12%
win, kept but minor. The real 8-16x lever is blocked on revert() restoring the SHARED
config/overlays.mk from git — designed, not built. An attempt to wire family_sweep's parallel default
broke it twice and was reverted rather than committed.
STUCK SINCE SESSION-21, and conform_decls was RIGHT to refuse it: the byte-true signature takes a
parameter while 138 zero-arg CALL SITES exist across 138 files, so conforming the declarations alone
would turn every one into `too few arguments` — a fleet-wide compile break the per-binary gate cannot
see. The tool printed the exact remedy in its refusal message and could not perform it, so the
function sat blocked for two sessions.
NEW --cast-zero-arg-calls: cast every 0-arg call site to ((s32 (*)(void))func_801789AC)() — gcc folds
the cast of a known symbol to a direct jal, so caller bytes are unchanged — then re-run the conform
normally. PLAN -> VALIDATE -> WRITE like the decl axis, because a partial cast set is itself a
fleet-wide compile break. Not a macro this time (unlike func_8015B950's single shared site): 138
genuine per-overlay call sites, one each.
VERIFIED IN STAGES, not all at once: the 138 casts ALONE are byte-neutral (d19c9580); then the
660-site declaration conform (axis complete, 0 remaining); then the gate -> verified 1 / failed 0;
then R22 clean-fleet 140 passed / 0 failed of 140.
Reach 138 x 91 ins = 12,558 templated instructions unlocked for the sweep.
137/137 banked, 0 failed. R22 clean-fleet 140 passed / 0 failed of 140.
MEASURED: fn-count 318,309 -> 318,447 (+138), crossing 90.03%; instr-weighted 83.8 -> 83.9%
(+15,180 ins); distinct-code +1 unique fn.
AN HONEST NUANCE: distinct-code moved only +1 here vs +126 for func_80176218's family, because these
137 members are byte-IDENTICAL (h_exact) and collapse to one distinct function, while func_80176218's
were genuine byte-VARIANTS. Both are real work; they move different metrics. The 3-metric dashboard
exists so one number cannot flatter the other.
This family banked only because conform_decls learned to read K&R definitions an hour ago: one tool
gap, unblocked, became 138 functions.
SESSION-22 TOTAL: 6 exemplars + 680 members = 686 functions.
THE GAP: conform_decls could not parse a K&R definition at all — it exited "no DEFINITION found,
refusing to guess". Honest, but §43 (a narrow param declared K&R-style, producing the in-place
`sll $a2,$a2,16` tell) is a documented, load-bearing idiom here for exactly the narrow-param class.
So the tool was silently refusing the drafts that most need it: a whole idiom family read as
"nothing to conform" (R32 coverage).
THE SUBTLE PART IS PROMOTION (C89 6.3.2.2). A K&R definition promotes each narrow parameter, so a
prototype in scope must declare the PROMOTED type or gcc rejects the pair with `argument 'x' doesn't
match prototype`. That is why the fleet prototype reads `s32 a2` for a parameter the definition
declares `s16` — and why emitting the declared (unpromoted) type would RE-CREATE the narrow-param
conflict this tool exists to remove. The parser now promotes s8/u8/char/s16/u16/short -> s32 and
float -> f64, pointers untouched, and reports (R32) any K&R param with no declaration.
RESULT: byte-true signature read as `void func_801330E0(void *, s16 *, s32)`; the only real change
vs the fleet's 973 declarations was param_1 `s16 *` -> `void *` (a pointer shape, caller-neutral).
973 sites / 973 files rewritten, axis complete. Gate: verified 1 / failed 0, d19c9580 BYTE-IDENTICAL.
R22 clean-fleet 140 passed / 0 failed of 140.
Reach 138 x 110 ins = 15,180 templated instructions unlocked for the family sweep.
The largest single family on the census: 137 siblings x 289 ins. Per sibling — jtbl_carve -> make
extract -> remap_hseq + canon_sig_reconcile -> whole-binary gate, revert-on-fail. 137/137 BANKED,
0 failed. R22 clean-fleet 140 passed / 0 failed of 140; report fail-closed green (dedup 1886/0,
C1 coverage 239604/239604, 0 NON_MATCHING).
MEASURED: fn-count 318,171 -> 318,309 (+138); instr-weighted 83.4 -> 83.8% (+39,882 ins);
distinct-code 72.5 -> 73.2% (+131 unique fns).
TWO TOOL REFUSALS MADE THIS BANK POSSIBLE, and both deserve recording:
- family_sweep REFUSED the family (has_mid_jr): §53's carve law says a carve-less sweep there returns
"a 0% that is a TOOL artifact, not a wall". Overriding with --allow-jr would have yielded 0/137 and
plausibly filed the highest-value family on the board as a wall.
- jtbl_family_bank REFUSED a dirty tree: its per-sibling revert restores from HEAD, so the
uncommitted 414-file decl axis would have been destroyed. H4 enforced in code.
This is the inverse of the session's earlier failures, which all came from tools that ANSWERED
instead of refusing.
SESSION-22 TOTAL: 5 exemplars + 543 members = 548 functions.
Fleet: 82.9 -> 83.8% instr, 71.5 -> 73.2% distinct-code.
The largest target on the T14 census: 138 members x 289 ins = 39,882 templated instructions at stake.
conform_decls --check showed 418 sites in 3 forms, pointer-type-only with NO narrowing warning and no
return-type change — the func_80179B74 shape that banked 137/137. Applied (418 sites / 414 files),
gated (jtbl carve succeeded first try), R22 clean-fleet 140 passed / 0 failed of 140.
Committed BEFORE the family bank because jtbl_family_bank refuses to run on a dirty tree — its
per-sibling revert restores from HEAD, so an uncommitted axis would be destroyed. The tool enforcing
H4 in code, correctly.
Also recorded: family_sweep REFUSED this family rather than returning 0/137 — func_80135EB0 is
has_mid_jr, and §53's carve law says a carve-less sweep there yields "a 0% that is a TOOL artifact,
not a wall". That refusal is the good version of today's pattern: every false wall untangled this
session (func_8016B6BC 0/137, the 4 fabricated CC1-FAILs, Phase-28's B2 0/8) came from a tool that
ANSWERED instead of refusing.
BANKED 273 member-matches / 0 failed across 137 overlays (func_8014CF04 136 + func_8015D1B8 137).
R22 clean-fleet 140 passed / 0 failed of 140; report fail-closed green (dedup 1886/0, C1 coverage
239604/239604, 0 NON_MATCHING).
MEASURED from the committed digests, not projected: fn-count 317,898 -> 318,171 (+273);
instr-weighted 83.2 -> 83.4% (+26,770 ins); distinct-code 72.3 -> 72.5% (+129 unique fns).
A USEFUL NEGATIVE RESULT: both families swept cleanly across ov_SC07_006/007/010/011 — the same four
overlays that refused func_80176218's sweep earlier today. So that set is not broken; the 4/137
refusal is family-specific (the _jr_8016AE5C.c carve), which is the per-sibling INTEGRATION signal
§59 describes rather than a codegen or overlay-level wall. Carried, still not concluded.
SESSION-22 total: 3 exemplars + 406 members = 409 functions.
THE BANK: the T14 PLUMBING census showed func_8014CF04 blocking THREE drafts at once. Conforming its
decl axis banked func_8014CF04 + func_8015D1B8 (func_80135260 is a genuine DIFF, agreeing with its
independent SESSION-21 diagnosis). R22 clean-fleet 140/140; report fail-closed green (dedup 1886/0,
0 NON_MATCHING). fn-count 317,896 -> 317,898; distinct 66,110 -> 66,111.
BUT THE AXIS WAS A 1,748-FILE T2 WRITE SET (the --check per-form counts read "1"), and R22 came back
139/140 -- TWICE -- on a change the per-binary gate called BYTE-IDENTICAL. Three defects (§98):
1. THE REGEX CROSSED NEWLINES. `[^;]*` matches '\n', so a match starting at a DEFINITION line ran
past the `{` to the first `;`, swallowing `s32 func_8014CF04(...) {` PLUS the register pin on the
next line and replacing both with a prototype -> undefined reference. Fixed to `[^;{\n]*`: a
definition is now unmatchable by construction.
2. IT REWROTE INSIDE COMMENTS (H5, 3 lines). Now scans cdecl._mask() and rewrites by SPAN (R33 --
that length-preserving primitive already existed for exactly this).
3. THE REAL CAUSE -- IT ASSUMED ONE SIGNATURE FITS THE FLEET. ov_SC07_006 carries its own banked
definition with a DIFFERENT byte-true signature ((s32,s32,void*) vs (s32,void*,void*)), under a
decl marked "per-overlay-local decl (byte-true sig); do NOT re-macroize". That is the Phase-16
loose-typing wall inside a tool that structurally assumes it away. NEW RULE: a TU that DEFINES the
function owns its own declarations; a fleet axis is meaningful only for CONSUMING TUs. This grows
more common as banking proceeds -- every overlay that banks a function becomes an exception.
Then the R32 completion assertion cried wolf on its own by-design skip ("HALF-AXIS -- DO NOT BUILD"
for a complete rewrite): an assertion must be exact about its DOMAIN, not just its condition. Scoped
to consuming TUs -> 1,747 sites, 1 excluded by design. Also hardened to PLAN -> VALIDATE -> WRITE;
the refusal path had aborted mid-write while claiming nothing was modified, creating the very
half-axis §85 calls a guaranteed break.
META (R22's premise, re-earned): after fixing defect 1 I EXPECTED R22 to pass; it failed again for an
unrelated reason, and an individual `make build` of the failing binary SUCCEEDED by reusing objects
the clean run rebuilds. An incremental pass does not refute a clean-tree failure.
+134 functions banked total for this exemplar (1 + 133 members). Measured from the committed
progress.fleet.md, not projected: fn-count 317,762 -> 317,896; instr-weighted 82.9 -> 83.2%
(+43,818 ins); distinct-code 71.5 -> 72.3% (+126 unique fns — these members are genuine byte-
VARIANTS that each count distinctly, not free dedup).
VERIFY: R22 clean-fleet (make clean && extract-all && check-all) -> 140 passed, 0 failed of 140.
make report fail-closed green: dedup-check 1886 validated / 0 failed, C1 coverage 239604/239604,
0 NON_MATCHING in any default build (G4).
THE 4 FAILURES ARE CARRIED, NOT CONCLUDED. All four are ov_SC07_006/007/010/011 and all four differ
from the other 133 in exactly one way: their sibling TU is _jr_8016AE5C.c, not _jr_801734BC.c —
carved under func_8016AE5C, which was banked and swept in SESSION-21. That is the SAME four overlays
and the SAME carve the SESSION-21 checkpoint flagged as "worth checking first" for func_8016B6BC's
0/137, which turned out to be a transitive type-carry (§94) rather than a wall. Each sibling reverted
its byte-neutral self-decl edit cleanly, so no dead diff is left behind. Per §59 a sweep failure is a
per-sibling INTEGRATION signal, not a codegen verdict — read one sibling's real gate result
(COMPILE-fail vs byte-DIFF) before concluding.
THE DRAFT was failing in a CHAIN, one "next conflict" per gate cycle. Applied §95's own diagnostic
law instead — splice once, dump EVERY cc1 error — and the whole set named the cause immediately:
three errors on TWO axes (one data decl, two callee decls), not three problems.
THE DATA ERROR WAS reconcile_tu AGAIN, ONE SHAPE DOWN (§96). split_statements returns comment-
STRIPPED text WITH SPANS; the rewrite re-found each planned statement by comparing that text to a raw
LINE, so `extern u8 D_80078E78; /* cur base ($s5) */` never matched. The decl was left unconformed
WHILE THE USE-CAST PASS STILL FIRED -> a draft whose uses are cast for the TU's storage against the
draft's own declaration -> cc1 reports `conflicting types` AT THE VERY DECL THE TOOL JUST CLAIMED TO
FIX, exit 0, "reconciled: 3 symbols".
FIX: rewrite by SPAN (the primitive existed — its docstring says spans are preserved *because drafts
get rewritten*). Plus the R32 assertion the old code was missing: it had a dropped_check counter
incremented in two places and NEVER COMPARED — "a loud failure nobody counts is exactly as invisible
as a silent one" in miniature. Now declarators-in vs -out AND a per-symbol check that each planned
tu.declaration() actually landed, both as `!!` notes so --strict exits non-zero.
MEASURED: 3 -> 4 data symbols reconciled on the same draft; trailing comments preserved (H5).
THE TWO CALLEE CONFLICTS were the other axis (reconcile_tu skips kind=='func' by construction):
cast_call_sites (§20) conformed func_80177AD4 (TU `void (int, unsigned int)`) and func_80178298
(TU `(u32*, u8*, short, short)`) and cast each call site to the draft's intended widths.
GATE: verified 1 / failed 0, d19c9580 BYTE-IDENTICAL. Write set is one overlay-local TU = T1 per the
§63/§85 blast-radius taxonomy, so the per-binary gate is sufficient; the ×137 sweep is the T2 case
and takes a full R22.
The family that failed its sweep twice (once in the 274-member batch, once after the §91 guard) and
looked like the §86 bimodal 'some families just don't template' case. It was not.
DIAGNOSIS (§59 + §93): spliced ONE sibling and read cc1 directly. It reported `c`, `v`, `off`
undeclared — ordinary locals that ARE declared in the remapped body. cc1 says 'undeclared' because it
aborted the declaration block at an unknown TYPE and every later declaration fell out with it. Read
the FIRST error, not the loudest: a visibly-declared variable reported undeclared means suspect its
type.
THE LIFT MUST BE TRANSITIVE. Lifting the type the body names directly (M8_8016B6BC) changed nothing —
still 0/137. The real set was four, found by following each definition's own references:
M8_8016B6BC -> Prim_8016B6BC -> Vtx_8016B6BC (named only inside Prim's body) -> DVec_8016B6BC.
lift_types.py --apply, byte-gated ALONE first (neutral, d19c9580 unchanged), then swept.
RESULT 0/137 -> 137/137, zero failures. R22 clean-fleet 140/140. cookbook §94.
Cost of not diagnosing: this family sat recorded as 'doesn't template' across two sessions. Pointed
at one sibling's real stderr it took under an hour and was worth 137 members.
WAVE 2 (9 never-drafted exemplars, ultracode): 9/9 returned, 5 MATCH / 4 near, 2.25M tokens.
BANKED: func_8014D820 (304 ins ×138) — and its agent ROOT-CAUSED the failure I left undiagnosed.
It was never an assembler problem: cc1 exit 33, `conflicting types for 'Ent'` vs
engine_types.h:434, surfaced by the recipe's `set -o pipefail` and MISATTRIBUTED to `as` because
`as` is the last stage in the pipe (Makefile:560). Fixed by moving V4/Desc/Ent to BLOCK scope —
byte-neutral and collision-proof across all 138 member TUs. Vindicates flagging it to the agent as
UNVERIFIED rather than passing my own guess forward as fact (§88e).
R22 clean-fleet 140/140.
NEW GUARD — SCALAR NARROWING IS NOT CALLER-NEUTRAL (byte-proven, and it cost 3 gate cycles):
conform_decls treated all decl type changes alike. A POINTER change is caller-neutral (func_80179B74
conformed 1,600 sites s16*/short* -> u16* and stayed byte-identical fleet-wide). A SCALAR WIDTH
change is NOT: narrowing `s32 a0` -> `u16 param_1` changes argument promotion at every call site.
MEASURED on func_80175DA8: decls reverted -> gate says PLUMBING; conform applied -> gate says DIFF.
The conform did not fix the draft, it changed the CALLERS. Now warned explicitly (not refused — the
draft's sig is still byte-truth for the callee and the gate arbitrates), with the instruction that a
DIFF after this conform means examine the callers (§17a-1 pair), not the body.
Verified the guard discriminates: fires on func_80175DA8 (s32->u16), silent on func_80179B74.
STILL OPEN from wave 2: func_80176218 + func_80175AB8 (DATA-symbol conflicts, D_80078EB4 /
D_8011F7BC -> reconcile_decls) · func_80175DA8 + func_80135EB0 (need the §17a-1 caller pair, not a
bare conform) · 4 near-misses with precise residuals recorded (func_80176734 129 length-drift,
func_80140958 49 inverted-hoist, func_80177B5C 19 sched tie, func_8017C974 83 -> permuter).
134/134 BANKED on the remainder after 3/3 on the probe — the FOURTH full-family sweep this session,
all four unblocked by the --like role guard, three of them 100%.
R22 clean-fleet: extract-all 139/139, check-all 140 passed / 0 failed.
1,600 decl sites across 523 files, in THREE different forms (s16 *a0 / short * / short *p),
conformed to the byte-true 'void func_80179B74(u16 *p)'. conform_decls ALLOWED this one: the arity
is unchanged, so no 0-arg call site can break, and the return is unchanged, so §85's precondition
does not apply. Gated BYTE-IDENTICAL; R22 clean-fleet 140/140.
The tool has now refused one axis (func_8015B950, correctly — it would have broken 138 binaries)
and cleared another (this one, correctly). Both verdicts held under R22.
133/134 BANKED on the remainder after 3/3 on the probe. ONE sibling refused (ov_SC03_108,
gate-fail) and is left as a stub rather than forced — a 136/137 recorded honestly beats a 137/137
that needed a shortcut. Third full-family sweep this session, all three unblocked by the --like
role guard.
R22 clean-fleet: extract-all 139/139, check-all 140 passed / 0 failed.
134/134 BANKED on the remainder after 3/3 on the probe — the second clean full-family sweep this
session, both unblocked by the --like role guard. func_8015B950 is stubbed in NO overlay.
R22 clean-fleet: extract-all 139/139, check-all 140 passed / 0 failed.
At 271 ins x 137 members this is the session's largest single family by instruction weight.
The same axis that broke 138 of 140 binaries an hour ago now lands clean, because conform_decls'
NEW arity guard located the actual obstruction instead of leaving me to absorb it by hand.
THE OBSTRUCTION WAS ONE LINE. Conforming `extern s32 func_8015B950(void)` -> `(s32 arg0)` turns
every 0-arg CALL SITE into `too few arguments`. My hand attempt assumed those were spread across the
926 TUs and would need 926 casts (the func_8012AAAC precedent, where it really was 137 separate
sites). They are not: there is exactly ONE call, in `src/shared/engine_core.h`'s
`DEFINE_func_8015BEE4()` macro body — expanded into all 926 TUs by the preprocessor.
func_8015BEE4 is a THUNK: `return func_8015B950();` with $a0 passing straight through from its own
caller. So the 0-arg call shape is byte-CORRECT and must be preserved, not fixed —
`return ((s32 (*)(void))func_8015B950)();` keeps it exactly (§17a-1; gcc folds the cast of a known
symbol to a direct jal, and the s32 return is unchanged so the thunk's value still flows).
Sequence: 1 cast -> conform_decls --apply (925 sites, R32 completion assertion: 0 remaining) ->
gate BANKED byte-identical -> R22 clean-fleet extract-all 139/139, check-all 140 passed / 0 failed.
The draft's 2 callee-decl conflicts (func_801725A4, func_80147078) dissolved with the axis.
Worth 37,398 templatable ins; the ×137 family sweep is next.
BANKED: func_8016AE5C (85 ins ×138). R22 clean-fleet 140/140.
⚠️ I BROKE 138 OF 140 BINARIES AND R22 CAUGHT IT — the per-binary gate could not.
Conforming func_8015B950's decl from `(void)` to its byte-true `(s32 arg0)` across 926 sites gated
BYTE-IDENTICAL on ov_SC01_077 and broke 138 other binaries with Error 33. §63/§85 exactly: a T2
write set is provable only by R22, and the binary the gate authorises is not the binary that breaks.
MECHANISM: conforming a decl to a signature that TAKES parameters makes every existing 0-ARG CALL
SITE a hard `too few arguments` error once a prototype is in scope. Not a declaration-only change.
PROCESS NOTE (mine): a first R22 reported 138 failures, an individual rebuild of a "failing" binary
said BYTE-IDENTICAL, and I nearly filed it as a flake. The second clean R22 reproduced it exactly —
the individual build passed only by reusing objects the clean run rebuilds. An incremental pass does
not refute a clean-tree failure; that is R22's whole premise, pointed at me. Reverted to a known-good
baseline (a stray jr_isolate region file was also in the tree) and redid the one good bank cleanly.
NEW tools/conform_decls.py — because applying this axis by hand three times in one session is how a
half-axis happens. Derives the byte-true signature from the DRAFT's definition (§58b), rewrites EVERY
site, asserts completion (R32). Encodes both preconditions: the §85 return axis (refuse if any caller
consumes the return) and a NEW arity precondition (refuse if 0-arg call sites exist, naming the cost).
The guard immediately gave a better diagnosis than my hand-fix had: func_8015B950's 0-arg call is in
ONE place — src/shared/engine_core.h, a DEFINE macro body — expanded into all 926 TUs. That fix is a
SINGLE cast, not 926 edits. Named as the next step rather than run on tired context.
Also lands cookbook §91 (the --like role trap) from the previous step.
- 134/134 BANKED on the remainder (after 3/3 on the probe) => the family is 137/137, ZERO failures.
func_8012AAAC is now stubbed in NO overlay. R22 clean-fleet: extract-all 139/139, check-all
140 passed / 0 failed.
- FLEET 81.9 -> 82.0% instr · 89.60 -> 89.64% fn-count · distinct-code 69.3 -> 69.5%.
- THE METRIC POINT, reproduced twice in one session and in BOTH directions: this jtbl family is
byte-VARIANT (each overlay's table holds its own addresses), so every member is a genuinely new
unique function and distinct-code MOVED. The h_seq PURE families swept earlier added 274 members
and moved distinct-code by +0.0, because those members were already counted via their shared
exemplar. SESSION-20's routing rule, now byte-demonstrated: target byte-VARIANT families to move
RE-completeness; high-reach h_exact families move only the display number.
- cookbook §91 — "a structure-TRANSFER is only valid where the structure corresponds": the --like
role trap, plus the three-hypothesis trail (two wrong, and instructive: the sibling call-site casts
were a real defect that fixed nothing, and my own carve-alone test was a false lead that departed
from the tool's real sequence). The law: any "same family => same structure" transfer must state
which structural fact it assumes and CHECK it on both sides — and a tool that drops an error class
it cannot act on should still SURFACE it, because a bare `gate-fail` repeated 137 times cost far
more than printing one line would have.
ROOT CAUSE of the 0/3 (found by reading the tool's ACTUAL invocation, not by guessing):
jtbl_family_bank calls `jtbl_carve <sibling> --func <fn> --like <exemplar_ov>`, and the role-transfer
keys on the SUBSEG ROLE (`ov_SC01_077_a` -> `_a`). Its premise — "same family => same span
structure" — silently breaks when the exemplar and the sibling host the function in subsegs with
DIFFERENT roles, which happens whenever the exemplar has a split the sibling does not.
MEASURED: func_8012AAAC lives in `ov_SC01_077_a` (role `_a`) in the exemplar but in the MAIN subseg
(role ``) in every sibling. The transfer therefore looked up `ov_SC01_077` — an unrelated SEVEN-table
span belonging to entirely different functions — and stamped those starts onto a sibling span holding
one table. jtbl_rodata_pads then refused with `consumed 1 rodata .align(s) but 2 pad spec(s) given —
table-count drift`, and jtbl_family_bank deliberately does NOT treat that error as isolate-fixable,
so all 137 siblings returned a bare `gate-fail` with the cause discarded.
THE FIX: transfer only when the exemplar's subseg for THIS FUNCTION has the sibling's role; otherwise
derive the span from the sibling's own carve (which was already computing it correctly). Fail-open is
not acceptable here — a wrong table set corrupts the image, so the guard defaults to local derivation.
MEASURED RESULT: the 3-member probe goes 0/3 -> 3/3 BANKED. R22 clean-fleet: extract-all 139/139,
check-all 140 passed / 0 failed.
Two earlier hypotheses were tested and are recorded honestly in CURRENT_PHASE.md: the sibling
call-site casts (real conflict, fixed, byte-neutral — but NOT the blocker) and my own carve-alone
test (which fails by construction for this shape, because a stub object does not emit the table its
2-entry spec describes — the tool splices the body BEFORE building, so its path is the valid one).
The ×137 member sweep returned 0/3, and §53/§86 say a 0% is a diagnosis task, not a verdict.
Diagnosed: every sibling TU has the IDENTICAL shape to ov_SC01_077 — the INCLUDE_ASM stub, then
'extern void func_8012AAAC();', then a 0-arg call LATER in the same file. Splicing the definition
in puts a prototype in scope, so gcc rejects the call with 'too few arguments' — the exact failure
the exemplar hit, reproduced 137 times.
Measured, not assumed: 137 sibling TUs hold BOTH the stub and a 0-arg call — exactly the member
count. Cast one call site per TU to ((void (*)(void))func_8012AAAC)() (§17a-1; gcc folds the cast
of a known symbol to a direct jal). The 137 'extern void func_8012AAAC();' DECLARATIONS were
deliberately left alone — an early count of '274 sites' was the calls AND the externs, and casting
an extern would have been meaningless churn.
Byte-neutrality PROVEN before committing, not asserted: R22 clean-fleet extract-all 139/139,
check-all 140 passed / 0 failed. This must be committed BEFORE the sweep because
jtbl_family_bank reverts each sibling from HEAD — an uncommitted fix would be reverted by the very
tool that needs it.
The first jtbl-routed bank of the session, and it validates the whole chain end-to-end:
1. jtbl_carve SPLIT-TABLE repair (this session): jtbl_801D7FB0 28 -> 50 words (112 -> 200 B),
authorized by func_8012AAAC's own `sltiu 0x32`.
2. NEW FIX — SINGLE-TABLE PREDECESSOR: adding a second table to a subseg whose existing carve was
single-table lost the FIRST table's start entirely (new_offs has only the new one;
overlay_jtbl_addrs cannot see the old one because its owner is banked and extract PRUNED the
stub .s; and single-table carves persist no tables= to rebase). The span then failed its own
validator with "first must equal the span start" — the invariant naming the missing entry.
A single-table carve spans exactly its one table, so ITS SPAN START *IS* THAT TABLE'S START:
inference, not persistence, so it also works for spans carved before tables= existed. This is
the RECOVERABLE half of the documented func_8013F350 lesson (that one was a pre-§8e merged
DOUBLE — two tables, no record, genuinely unrecoverable).
Result: ov_SC01_077_a JTBL_PADS := 0,0 tables=+0x0,+0x14. Carve alone byte-gated BYTE-IDENTICAL
BEFORE the bank was attempted (§81 step 2).
3. ARITY axis, all-or-nothing: 1,244 decl sites / 1,240 files `(void)` -> `()` + an R32 completion
assertion (old-form remaining: 0).
4. ONE call-site cast: the definition lands at line 811 and a 0-arg call sits at 822, so gcc sees
the prototype and rejects it — `((void (*)(void))func_8012AAAC)()` (§17a-1; gcc folds the cast
of a known symbol to a direct jal). Only 1 of the 1,386 fleet-wide 0-arg call sites needed it:
the others see only the `extern ()` decl, which permits a 0-arg call.
DIAGNOSIS NOTE: the failure read CC1-FAIL with only a warning visible under make. Running the
pipeline stage-by-stage (cpp | cc1 | maspsx | jtbl_rodata_pads | as) put it on cc1 rc=33, and cc1's
own stderr named it exactly: "too few arguments to function func_8012AAAC" at line 994. Isolating
the stage was what turned an opaque Error 33 into a one-line fix.
R22 clean-fleet: extract-all 139/139, check-all 140 passed / 0 failed.
family_sweep correctly REFUSED this exemplar (§53: a jr-family must route through
jtbl_family_bank.py; "a 0% from this path would be a TOOL artifact, not a wall") — the ×137 member
sweep is the next step and needs a clean tree, which this commit provides.
- family_sweep --hseq over the 3 newly-banked exemplars: BANKED 274 member-matches / 137 failed
across 137 overlays, for ~0 agent tokens. Session total: 3 exemplars + 274 members = 277 fns.
- THE STALE-MAP STEP, hit and handled: the first sweep returned "0 matched-exemplar families"
because .run/family_hseq.json still listed the fresh cracks as draft-ov077. Regenerated
(matched-sib families 60 -> 63) and the sweep found them — the documented bank-x1 -> regen ->
sweep path (memory crack-wave-sweep-map-regen).
- §86 REPRODUCED CLEANLY: 2 of 3 families templated ~137/137; the third failed ~137/137. Not a
rate — a BIMODALITY. One probe per family, then sweep or skip; never a blended pool average.
- R22 clean-fleet: extract-all 139/139, check-all 140 passed / 0 failed (second clean-tree
verification this session). dedup 1886/0, C1 coverage 239,604/239,604, 0 NON_MATCHING (G4).
- FLEET 81.7 -> 81.9% instr · 89.52 -> 89.60% fn-count · distinct-code 69.3% UNCHANGED — correct
and expected: these are h_seq PURE propagation-class families, and SESSION-20's routing rule says
propagation moves only the DISPLAY metric (members were already counted once via their exemplar).
To move RE-completeness, target byte-VARIANT families. Stated plainly so the next session picks
targets by the metric it means to move.
- drive-by: family_sweep --help crashed (argparse %-expands help text; a literal "0%" needed "0%%").
BANKED (whole-binary byte-gate, the sole arbiter): func_8014D2A0 (80 ins ×138) · func_80158638
(87 ×138) · func_8016B6BC (94 ×138). Stubs in ov_SC01_077: 150 -> 147, 0 new stubs.
R22 CLEAN-FLEET: extract-all 139/139, check-all 140 passed / 0 failed. dedup 1886/0,
0 NON_MATCHING (G4). Fleet 81.7% instr / 69.3% distinct-code / 89.52% fn-count.
- WAVE STOPPED at Drew's request with 15/24 agents returned, ALL 15 status=match. Only the
completed drafts were gated; in-flight ones are still being written (§90d).
- PRE-GATE, both oracles, all 15: match_one MATCH + reloc_verify ALL RESOLVED. Routed 7 plain /
8 to the §81 jtbl carve chain.
- THE BLOCKER, MEASURED: 7 of 7 plain drafts failed PLUMBING, 0 DIFF, 0 compiler walls — the same
shape as SESSION-20's T0.2. §58b applies: the draft sig is byte-TRUTH (it MATCHed), the header
decl is the stale stub-era guess, so conform the DECLS.
- §85 RETURN-AXIS WIDEN, all-or-nothing: 3,471 decl sites / 1,736 files, precondition verified
(ZERO callers consume the return => byte-neutral by construction) + an R32 completion assertion
(old-form decls remaining: 0). func_8014D820's s32 return is load-bearing — forcing `void` costs
2 instructions (302 vs 304), so the decls had to move, not the draft.
TWO HONESTY ITEMS:
1. I REPORTED "0 of 7 banked"; the true number was already 2. My diagnostic pass printed only
lines starting with "- func_" (the failures) and hid its own successes while I read it for
error text. A script that prints only failures cannot tell you it succeeded — the R32
silent-skip shape aimed at my own instrumentation. Ground truth is the stub count (§55b(3)).
2. A REAL FINDING fell out of that mistake: same drafts, same tree, minutes apart — gate_stage's
full ladder banked 0/7 while bare harvest_verify banked 2/7. The LADDER REGRESSED two drafts
the bare gate accepts (§19's "sig_unify regresses already-canonical drafts", one level up, and
the exact mirror of SESSION-20's missing-ladder false 33%). Neither "always ladder" nor "never
ladder" is right — run both, let the byte-gate arbitrate. One build per draft.
OPEN: func_8014D820 still a stub — after the widen its error moved from `conflicting types` to an
assembler-stage failure, not finished diagnosing. Recorded as open, NOT as a wall.
Zero functions >1000 ins remain unmatched anywhere in the fleet.
func_80183814 (5,122 ins — the LARGEST function in the game) — round 2 closed it: length 5127->5122
exact, structural residual 36->0, register-sensitive 1201->0, frame -256 -> -0xF8 exact, saves
10 -> .mask 0x807f0000 exact. Verified independently (R14): match_one MATCH (5122 ins).
ROUND 1's DIAGNOSIS WAS WRONG and the agent refuted it properly: the +5 length was a SYMPTOM, not
the lever, and the §83d max_reg/cse.c:8340 story does not hold — a 15-line reproducer reproduced the
case-0/3 CSE exactly (so it cannot be max_reg-gated), max_qty only gates extension ACROSS blocks,
and the target leaves $s7/$fp unused (no pressure story). Confirmed from a second direction: C01 has
the identical two groups over the identical symbols with ZERO residual, because a `break` puts a
CODE_LABEL between them. The two biggest levers were pure DECLARATION SCOPE (§45/§76), not pins.
func_8017DC1C (1,518) — MATCH first round, pin-free, zero __asm__ dials. NOT a jr fn (0 mid-fn jr).
func_8017D2DC (1,586) — MATCH first round (banked in the previous commit).
BANKING ORDER MATTERS — a new failure mode found and worked around: banking func_8017DC1C BEFORE the
carve chain broke the build. Its draft establishes the canon for 39 previously-undeclared externs;
jr_isolate_all's re-partition (overlay_src_split) then DROPPED ALL 39 across the new split boundary
(`D_801C1EB0 undeclared`), leaving them in NEITHER file. The §77 preamble-drop class, in a third tool.
FIX = ordering, not patching: run the §81 carve chain FIRST on a clean tree (gated BYTE-IDENTICAL),
then bank. Reverted, re-sequenced, both banked clean.
R22 clean-fleet 140/140 BYTE-IDENTICAL; tools-health OK; dedup 1886/0; 0 NON_MATCHING (G4).
Fleet: instr 81.6 -> 81.7% · distinct-code 69.1 -> 69.3% · fn-count 89.52%.
T0.7 — the §86 one-member probe applied to the remaining FREE families: 9 LIVE / 6 DEAD / 5 unstaged.
The three highest-value families by raw size (18,084 / 11,234 / 10,880 ins) all probed DEAD — the
probe skipped them instead of burning ~400 gate cycles rediscovering it. Swept the 9 live: 104 banked,
8 of 9 families fully cleared (func_8017BEF8 has 8 stragglers).
BEHEMOTH 2 of 3: func_8017D2DC (1,586 ins, ov_SC01_001) MATCHED and BANKED — closed in ONE agent
round, pin-free. Verified independently (R14): match_one MATCH (1586 ins).
§81 carve chain: the agent predicted step 1 unnecessary; jtbl_carve REFUSED (the subseg already
hosts a .rodata carve and the new table's start != span start). The refusal was RIGHT and is the
instruction to run step 1 — jr_isolate_all --only (2 fns/1 object) -> BYTE-IDENTICAL, then
jtbl_carve -> BYTE-IDENTICAL, then the ladder banked it.
R22 clean-fleet 140/140 BYTE-IDENTICAL; tools-health OK; dedup 1886/0; 0 NON_MATCHING (G4).
Fleet: instr 81.5 -> 81.6% · distinct-code 69.0 -> 69.1% · fn-count 89.49 -> 89.52%.
The §42e pin guard refuses any family whose exemplar carries `register __asm__` pins: 680 of the top
8 FREE families' 1,083 members (63%) were skipped BEFORE any gate ran. Re-run with --allow-pins,
letting the byte-gate arbitrate (G3/P9): 268 banked, and ZERO cc1 crashes across hundreds of pinned
compiles — confirming the SIGABRT the guard was written against was Phase 27's extract_unit
macro-drop, NOT a compiler limit. The guard is protecting against a bug that no longer exists.
THE LAW (§86): templatability is a PER-FAMILY property, not a per-member rate.
func_801749C8 137/137 = 100% func_80133AB0 4/136
func_8014C6F4 137/137 = 100% func_8014CF04 0/137
func_80143D28 0/136
Two families at 100%, three at ~1%. MY REPORTED "37%" WAS AN ARTEFACT: a 19-member sample that
straddled families reported their AVERAGE and hid the bimodality. Sample PER-FAMILY, never per-pool.
=> PROCEDURE, now the default: probe ONE member per pinned family; bank -> sweep the family; fail ->
skip entirely. The blanket sweep spent ~412 futile gate cycles (60% of the run) on three families
that were never going to bank; the 1-member probe reduces that to 5 probes + 2 sweeps.
Left explicitly UNDIAGNOSED (do not guess): why two families template and three do not. Likely axis
is caller-saved pins spanning a `jal` (§74's corrupting form) vs pins fixing only a local allocno.
Diagnose BEFORE extending --allow-pins fleet-wide — the byte-gate makes a wrong guess free, but a
wrong PROCEDURE costs a sweep.
R22 clean-fleet 140/140 BYTE-IDENTICAL; tools-health OK; dedup 1886/0; 0 NON_MATCHING (G4).
Fleet: instr 81.3 -> 81.5% · distinct-code 69.0% · fn-count 89.41 -> 89.49%.
Re-derived the T0.1 decomposition post-harvest (it was stale by 395 banked members):
zero-crack pool 76 fams / 347,892 ins -> 73 fams / 290,850 ins (the harvest came out of it)
FREE (sweepable, non-jr, non-O0) -> 58 fams / 167,368 ins
Swept the top FREE families through the gate_stage ladder (sample 8/8 first, then the rest):
389 banked; func_801463A0 / func_8017B490 / func_80156670 now stubbed in ZERO overlays.
R22 clean-fleet 140/140 BYTE-IDENTICAL; tools-health OK; dedup 1886/0; 0 NON_MATCHING (G4).
Fleet: instr 81.0 -> 81.3% (10,645,711 -> 10,683,424) · distinct-code 68.8 -> 69.0% ·
fn-count 89.30 -> 89.41%.
THE BLOCKER HAS MOVED — it is now OUR OWN PIN GUARD, not gcc and not declarations. Of the 1,083
candidate members in the top 8 FREE families, 680 (63%) were refused by the §42e pinned-exemplar
guard BEFORE any gate ran; only 403 reached staging. Two pieces of evidence say the guard may now be
over-conservative: SESSION-19 banked func_8017A4AC x134 WITH pins once the byte-gate arbitrated, and
Phase 27 dissolved the cc1 SIGABRT that motivated it (it was the extract_unit macro-drop, not a
compiler limit). Next probe: --allow-pins on a sample of 8, byte-gated.
MY OWN SCRIPT BUG, fixed + negative-controlled: the sweep loop globbed `.run/sweep/*/`, which also
matches gate_stage's INTERMEDIATE ladder dirs (-cn, -cn-cast, -cn-cast-rc, -s2in, -s2in-uni). Those
were called as if they were binaries -> 24 phantom "PARTIAL 0/1" lines inflating notbanked to 56 when
the true failure count was ZERO (stub counts 0/0/0 are the ground truth). Fixed by requiring
config/splat.<ov>.yaml to exist; negative control confirms phantoms are skipped and real binaries kept.
The derived-offset recompute swept the whole func_8013D53C family: 119 banked / 0 failed on top of
the 4 earlier; func_8013D53C is now stubbed in ZERO overlays. R22 clean-fleet 140/140 BYTE-IDENTICAL;
tools-health OK; dedup 1886/0; 0 NON_MATCHING (G4).
RECIPE (and it is NOT the return-axis recipe — sampling caught this):
§84 derived-offset -> per-member literal recompute AND the gate_stage ladder.
With the recompute alone the sample was 0/8; through the ladder it was 3/3, then 119/119.
Had I reused the return-axis recipe (plain harvest_verify, which banked 272/272 there) I would
have swept 123 members to zero banks and mis-concluded the fix was wrong. Probe-before-scale.
METRIC FINDING worth carrying: this harvest moved instr +29,280 AND distinct-code +27,840, while the
return-axis harvest moved instr +26,928 and distinct-code +0. §84-class members are byte-VARIANTS so
each is a new unique function; propagation-class members were already counted once via their shared
exemplar. => §84-class work moves the RE-COMPLETENESS number; propagation moves only the DISPLAY one.
Session fleet: 80.6 -> 81.0% instr · 68.2 -> 68.8% distinct-code · 89.18 -> 89.30% fn-count.
THE §85 WIDEN PAID OFF AS PREDICTED. It is a ONE-TIME fleet edit, so once committed the
`conflicting types` blocker was gone for EVERY member of both families at once:
- sample 8 first (probe-before-scale): 8/8 banked with PLAIN harvest_verify, no ladder needed
- full sweep: 264 banked / 0 failed across 132 overlays; 10 skipped as not-stub
- total 272 members ~= 27k ins, ZERO agent tokens
R22 clean-fleet 140/140 BYTE-IDENTICAL; dedup 1886/0; 0 NON_MATCHING (G4).
Fleet: instr 80.6 -> 80.8% (10,589,503 -> 10,616,431, +26,928) · fn-count 89.19 -> 89.26%.
distinct-code UNCHANGED at 68.3% — propagation moves the DISPLAY metric, not the RE-completeness
one (the SESSION-19 split, reconfirmed).
§84 RECOMPUTE now implemented in tools/family_remap.py (fix_derived_offsets), wired into all three
apply_remap call sites as a PRE-pass on the exemplar body (the literal is ambiguous as a substitution
token, so it cannot be a table entry):
correct_literal = mapped(aliased_sym) - mapped(base_sym)
Verified by negative control: the hand-solved case recomputes 0x20 -> 0x18 exactly, and a site whose
target endpoint is NOT a mapped symbol is left byte-for-byte alone AND REPORTED in info
["derived_offsets"] (R32 — a silent skip is a defect, and a silent skip is how this bug survived).
Continues the "see why and try again" chain. Diagnosed all 4 T0.2 failures to 4 DISTINCT causes:
func_8013D53C 240x123 §84 derived-offset remap bug -> BANKED (previous commit)
func_8012CC88 105x137 §73/§30#2 RETURN-axis conflict -> BANKED here
func_8014D12C 93x137 §73/§30#2 RETURN-axis conflict -> BANKED here
func_80144090 154x136 LENGTH-DRIFT (+13 B, ~3 ins long) -> genuine codegen, real work
THE FAILURE THAT TAUGHT THE FIX: widening only src/shared/engine_core.h banked the member in the
TARGET overlay and BROKE ov_SC01_077 (R22 139/140) — the source overlay carries its OWN local
`extern void func_X(...)` decls, so a shared-header-only widen puts them in direct conflict. The
per-binary gate passed while breaking a binary it never built (§63/§61: a T2 write set is only
provable by R22). A half-done axis is a guaranteed break, not a smaller win.
THE FIX: do the WHOLE axis — 3,668 `extern void` decl sites across 2,688 files widened to `s32`,
0 remaining (R32 completion assertion). Precondition verified first: 0 callers consume the return
value, so the widen is byte-neutral by construction. R22 clean-fleet 140/140 BYTE-IDENTICAL;
tools-health OK; dedup 1886/0; 0 NON_MATCHING (G4).
MY OWN ERROR, recorded (§85 trap): I first spot-checked ov_SC01_077 with
`make build | grep | head; echo rc=$?` and read rc=0 as success — that is the exit status of `head`,
not make, and the output had no BYTE-IDENTICAL line. I reported a false BYTE-IDENTICAL in the
interim. Assert on the SUCCESS STRING, never on $? after a pipe.
Fleet: instr 80.6% (10,589,503) · distinct-code 68.3% (3,846,656) · fn-count 89.19%.
Drew: "if it fails, see why and try again with new knowledge." It failed twice, then banked.
ROOT CAUSE, byte-proven: a family_remap member reached match_one MATCH (240 ins) and failed the
whole-binary gate by ONE BYTE. The exemplar carries a deliberate matching idiom — reach a symbol via
a DIFFERENT symbol plus a literal offset, so gcc cannot CSE the two %hi/%lo pairs:
(*(S9*)&D_801DAA78) = *(S9*)(&D_801DA998 + 0x20); /* same addr as &D_801DA9B8 */
family_remap substitutes the symbol NAMES correctly and leaves the literal 0x20 — but 0x20 is not a
constant of the algorithm, it is the DISTANCE BETWEEN TWO PER-OVERLAY SYMBOLS:
exemplar 0x801DA998 + 0x20 = 0x801DA9B8 OK
member 0x801A5778 + 0x20 = 0x801A5798 WRONG (real symbol 0x801A5790)
member 0x801A5778 + 0x18 = 0x801A5790 correct
match_one MASKS HI16/LO16 so it is STRUCTURALLY BLIND to this — the §81 blindness in its DATA form.
TWO FIXES WERE EACH INDIVIDUALLY INSUFFICIENT: the byte fix alone re-failed as PLUMBING; the ladder
alone re-failed as DIFF. Together -> BANKED, R22 clean-fleet 140/140.
TWO LADDER CORRECTIONS (my own T0.2 error): bare harvest_verify is the LAST RUNG, not the ladder —
gate_stage runs canon_resident_calls -> cast_call_sites -> reconcile_tu -> ARITY -> sig_unify ->
harvest_verify, so T0.2's "8/8 PLUMBING" measured the UN-RECOVERED rate. And reconcile_decls.py is
RETIRED (R33, superseded by reconcile_tu): asking "what does the FLEET call this symbol?" is wrong by
construction in a loosely-typed engine (548 of its answers conflicted, rewriting 60 of 196 drafts) —
so Drew's suggested tool would have made it worse.
SCOPE, MEASURED (not over-generalised, §80): the idiom appears at only 5 sites corpus-wide — BUT one
gates a 123-member family (133 staged drafts all carry the un-recomputed +0x20 with different
per-overlay bases), so the mechanical fix is worth ~240 ins x 123 ~= 29,520 ins. It does NOT explain
the pool generally: func_80144090 / func_8012CC88 / func_8014D12C have ZERO derived-offset sites and
fail for a different, still-undiagnosed cause.
THE FIX IS MECHANICAL: correct_literal = mapped(aliased_sym) - mapped(base_sym). The remap already
holds both mappings, and the exemplar's own comment names the aliased symbol.
Also observed: the ARITY pre-pass left 40 TUs of caller-decl edits after a 0-bank run (same hygiene
bug as --normalize-self-decls, twice in one session) — reverted, both binaries byte-identical.
MEASURED, not projected (R14): 12 gate attempts across ov_SC01_000 + ov_SC01_001, one draft per
build for clean attribution.
- 4 BANKED (func_8017B490 x2, func_801463A0 x2); 8 failed; **0 DIFF — zero compiler walls**
- all 8 failures are the §75a/def-side declaration class: `conflicting types for 'D_800A651C'`
(DATA sym) and `conflicting types for 'func_8013D53C'` (the member's OWN def-side decl)
- => raw conversion 33%, but the ceiling is NOT 33%: the blocker is declaration plumbing, which
this project has named tools for. Plumbing recovery has out-earned drafting in every phase that
measured both (P19 fix_arity_callers, P28 dedup_extend 6,174 members / 95.6% from one new mode)
TWO CORRECTIONS TO MY OWN T0.1 POOL MATH, both downward:
- 2 of the 8 top "FREE" families were refused outright by the §42e pinned-exemplar guard (the 270
skips) => "FREE" does NOT imply sweepable; pins are a third blocker the decomposition missed.
Recoverable (--allow-pins; SESSION-19 banked pinned families x134), but I mis-labelled them
- n_templatable counts the matched exemplar, so every T0.1 family figure is ~1 member (~0.7%) high
NEGATIVE RESULT (§80, scoped to this base): --fix-def-sig REGRESSES this class — 0 banked and 2
PLUMBING became CC1-FAIL despite targeting the same error text. Do not re-buy without re-testing.
NAMED NEXT LEVER: family_sweep --normalize-self-decls, whose help text cites fixing "the conflicting
types for func_X that blocked 133/137 of func_801670E4" — exactly this failure. Gate-phase transform,
so it cannot run under --stage-only, and --limit caps FAMILIES not MEMBERS => needs a full ~123-member
family run. Highest-value outstanding probe, zero agent tokens.
R22 clean-fleet 140/140 BYTE-IDENTICAL; tools-health/dedup 1886/0; 0 NON_MATCHING (G4).
Fleet: instr 80.6% (10,589,065) · distinct-code 68.3% (3,846,416) · fn-count 89.19%.
The SESSION-19 handoff's item 1, closed as specified — no drafting, no agent.
- §77 MINIMAL CLOSURE (519 lines, not the 2,993-line whole-file carry): 18 gte_* macros
+ 5 externs + the bandsetup static-inline helper -> match_one MATCH (1061 ins)
- §81 chain, each step byte-gated before the next: jr_isolate_all --only (2 fns/1 object)
-> BYTE-IDENTICAL; jtbl_carve --func (single-table, 44-piece interleave) -> BYTE-IDENTICAL;
harvest_verify --chunk 1 -> verified 1 / failed 0, 7042bc71 BYTE-IDENTICAL
- R22 clean-fleet 140/140 from a genuinely clean tree; tools-health OK; dedup 1886/0;
0 NON_MATCHING (G4). FLEET distinct-code 3,845,161 -> 3,846,222 = 68.3% (+1,061, all
distinct — a behemoth-class bank, not a propagation); instr-weighted 80.6%
- No §75a class spoke: the exemplar's ApplyMatrixSV(void*,void*,void*) canon fix was
already carried, so the declarations were clean and it banked first try
- cookbook §77: the ladder CLOSED with all four rungs measured (-56 -> -34 ->
MATCH-but-uncommittable -> MATCH+BANKED), plus a NEW subsection — the CANDIDATE gate
and the REAL gate need DIFFERENT preambles (match_one compiles standalone, so a
shared-type body's CC1-FAIL is a report about the PROBE, not the draft; the types
header goes in a throwaway probe copy, never in the banked draft)
- FINDING, flagged not acted on (P5d): that shortcut already leaked an ABSOLUTE include
path into 21 git-tracked files / 23 lines. All 21 verified semantically no-op (guarded
engine_types.h via engine_core.h at line 2) => removal is byte-neutral, but cpp must
still find the literal path, so those TUs cannot preprocess on any clone not at
/home/musashi/bfm-decomp. Invisible to every byte-gate (R34's null-oracle shape, aimed
at portability). Proposed as the next task.
- CRACKED at xHigh and VERIFIED INDEPENDENTLY: match_one MATCH (1061 ins); agent re-matched 3x
from clean runs (100% register-masked AND register-kept, all 10 regions, frame 0x270 exact).
§81 carve chain clean first try: jr_isolate_all --only -> byte-identical cacaf7c2 -> jtbl_carve
(43-piece set) -> byte-identical -> bank -> R22 clean-fleet 140/140, tools-health OK.
instr 80.6%; distinct-code 3,844,100 -> 3,845,161.
- WHAT IT IS: the matched base func_8017CA80 + camera height-band cull + distance-driven CLUT
fade. func_8004974C (TransposeMatrix) sits in a 36-ins prologue deriving a Y band; the
part-level `lim >= g.otz` cull is GONE; flat arms gain an `sz < lim` near-plane cull. The
base+one-extra-callee fingerprint predicted this exactly.
- §82 ORACLE 1 -- A DUPLICATED `addiu $aN,$sp,K` ACROSS A `jal` MEANS THE BLOCK WAS INLINED.
`&X` on any non-first local always creates a pseudo and CSE always merges two of them
(expr.c:6260 ADDR_EXPR -> force_operand(..., NULL); exception: virtual-stack-vars offset 0).
So the same stack address re-materialised at two sites separated by a jal means CSE was
PREVENTED from merging => not the same function body. 17 non-inline spellings failed; a
`static inline` helper reproduced the prologue BYTE-FOR-BYTE first try. Reusable probe: scan
the ~1,200 built objects for that signature in NON-INCLUDE_ASM functions.
- §82 ORACLE 2 -- SCALAR vs AGGREGATE DECIDES *WHEN* A STACK SLOT IS ALLOCATED: lazily at first
`&` for a scalar, AT DECLARATION for an aggregate. Six GTE result words had to be six separate
longs, not a struct, or they don't land after the inlined helper's temps and the frame isn't
0x270. Second-order: it also flips MEM_IN_STRUCT_P (§30's /s) -- with one word a fixed-address
scalar, ((PolyF3*)pkt)->rgbc stops aliasing it, so a store needed respelling to keep the
target's nop. A scalar-vs-struct choice is simultaneously a frame-layout AND an aliasing
decision.
- BANKING FOOTNOTE (§75a class A): first bank rejected `conflicting types for ApplyMatrixSV` --
draft (MATRIX2*, SVECTOR2*, SVECTOR2*) vs the TU/fleet canon (void*, void*, void*), 2,286 of
2,835 sites. Conforming the decl is byte-neutral and banked first try. On a jr function expect
BOTH gates to speak: the carve chain answers the jump table, §75a answers the declarations.
- Also reproduced: §78 (reuse a busy variable), §80(i) (a lever went -8 -> exactly neutral as the
base moved), §72 (a register pin made it worse).
- AGENT'S OWN CAVEAT, recorded not hidden: one zero-byte __asm__ keeps a vestigial `mnc = hmid`
alive that flow.c would delete (costing 10 ins + the 0x130 spill slot). Emits nothing, compile
is 1061 exact, but it is a documented stand-in -- 12 natural spellings measured, all DCE'd.