Commit Graph

534 Commits

Author SHA1 Message Date
Drew T a776d3248b feat(phase-29): func_8014CF04 + func_8015D1B8 families swept 273/273 (R22 140/140)
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.
2026-07-27 17:56:18 -06:00
Drew T 34a37ef0ea docs(phase-29): SESSION-22 checkpoint — 136 functions banked, 4 tool defects fixed (§96/§97/§98) 2026-07-27 17:48:52 -06:00
Drew T ad57c16e61 feat(phase-29): func_8014CF04 + func_8015D1B8 banked; conform_decls had 3 defects R22 caught (§98)
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.
2026-07-27 17:47:57 -06:00
Drew T 97cd2739b5 fix(phase-29): the gate manufactured 3 false CC1-FAIL verdicts — carve-refusal, tree hygiene, R32 (§97)
A 15-draft harvest_verify batch reported CC1-FAIL=4 and `final SHA None`. Three of the four were the
HARNESS, not the compiler. Checked the tree FIRST (the MISMATCH is a tree alarm, not a result),
reverted to the committed baseline rather than reasoning about a half-applied state, rebuilt ->
d19c9580 BYTE-IDENTICAL. No banked result was ever at risk: the byte-gate cannot manufacture a match,
but it CAN manufacture a verdict — and verdicts are what the backlog and roadmap are built from.

ORDERING PROVED THE CASCADE (R14): items 1-11 are real (9 PLUMBING, 2 DIFF), all before item 12 —
jtbl_carve REFUSING func_8013B83C (§59(3) non-contiguous same-subseg table). Items 13-16 are four
CC1-FAILs on the SAME ov_SC01_077_o0.o = one refused carve counted four times.

THREE DEFECTS FIXED:
1. `_ok` was computed and IGNORED — a refused carve was spliced and built anyway into a guaranteed
   Error 33, filed as CC1-FAIL. Now a named CARVE-REFUSED class, skipped (one build cheaper).
2. attempt() never restored on failure, so the tree was dirty BETWEEN drafts — and _jtbl_snapshot()
   snapshots the tree AS IT FINDS IT, so a later carve captured an earlier FAILED draft's splice and
   its undo faithfully RE-APPLIED it, after the final _write(baseline). That is the entire
   `final SHA None` mechanism. Invariant restored: the tree is at baseline except while a draft is
   under test (atomic AND bisect branches).
3. The recovery's own `make extract` rc was unchecked (_sh does not raise — §93's sibling). Now loud.
Plus an R32 assertion on the cleanup: at 0 verified a non-empty git status is residue, not a result;
it names the files and the recovery command. It fired correctly on its first real run.

MEASURED RECOVERY (same drafts, clean tree): func_8013B83C -> CARVE-REFUSED; func_801789AC ->
PLUMBING (actionable); func_8017C974 -> DIFF (corroborates its agent's global_alloc spill diagnosis);
func_80140958 -> CC1-FAIL (genuinely its own). final SHA None -> d19c9580; tracked diff empty.

BLAST RADIUS OF §96, HONESTLY: the reconcile_tu span fix unblocked func_80176218 (banked, swept
133/137) and no other draft in the batch. 7 of the 9 PLUMBING are `conflicting types for <the
function itself>` = the DEF-side self-decl axis conform_decls owns — the next lever, now a measured
target list rather than a guess. cookbook §97.
2026-07-27 17:17:54 -06:00
Drew T ea1d6587d6 feat(phase-29): func_80176218 family swept 133/137 (R22 140/140)
+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.
2026-07-27 17:07:03 -06:00
Drew T 8c36ede849 feat(phase-29): func_80176218 banked (45,126 templ ins) + reconcile_tu span/R32 fix
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.
2026-07-27 16:55:02 -06:00
Drew T 553949d157 docs(phase-29): SESSION-21 final checkpoint + cookbook §92/§93 (the doc gap Drew caught)
CHECKPOINT HYGIENE: between T11 and T12, wave 2 + a bank + a new tool guard were recorded ONLY in
commit messages — CURRENT_PHASE.md and the cookbook were stale for that stretch. The quiet periods
were background sweeps/R22 (~2h each) during which the tree cannot be touched, but that does not
excuse leaving the durable record behind: a stale checkpoint is worse than an absent one. Closed.

cookbook §92 — conforming a DECLARATION: pointer changes are caller-neutral, scalar-WIDTH changes
are NOT. Byte-proven both ways (func_80179B74: 1,600 sites / 523 files / 3 forms, banked, R22
140/140; func_80175DA8: PLUMBING before the conform, DIFF after — the conform did not fix the draft,
it changed the callers). Plus the arity case that broke 138/140, and the counting lesson:
func_8015B950 looked like ~926 call-site casts and needed ONE — its only 0-arg call sits in an
engine_core.h DEFINE macro the preprocessor expands 926 times. Count SITES, not expansions.

cookbook §93 — `set -o pipefail` attributes a pipeline failure to the LAST stage, not the failing
one: cc1 exit 33 reads as an assembler error because `as` ends the recipe. The 2-minute fix is to run
the stages by hand printing each rc, then re-run the failing one with stderr visible. Turned an
opaque Error 33 into a one-line fix twice today. Corollary (§88e, earned): hand a stuck function over
as an UNDIAGNOSED observation, never as a named cause — flagged that way, the agent found the true
cause (cc1 `conflicting types for 'Ent'`) immediately.

func_8014D820 family swept 137/137. func_8016B6BC 0/137 reproducibly — recorded as a DIAGNOSIS task
per §59 (a sweep 0/N is a per-sibling integration signal, not a codegen verdict), never as a wall.
Checkpoint fn-count corrected 89.88 -> 89.80 against the measured report; stray a.out removed (R12).
2026-07-27 16:03:14 -06:00
Drew T 42e9eaba55 docs(phase-29): T11 — func_80179B74 137/137; paused for the effort toggle before the wave 2026-07-27 14:02:46 -06:00
Drew T e721452526 feat(phase-29): 3 more exemplars banked + 3 family sweeps; conform_decls extern-optional fix
BANKED: func_8015B950 (271 ins) · func_8016AE5C (85) · func_80179B74 (111).
SWEPT: func_8015B950 137/137 · func_8016AE5C 136/137 (ov_SC03_108 refused, left a stub rather than
forced). Three full family sweeps this session, all unblocked by the --like role guard.
FLEET 82.4% instr · 70.4% distinct-code (crossed 70%) · 89.72% fn-count. R22 140/140 throughout.

conform_decls has now been right in BOTH directions: it REFUSED func_8015B950 (which by hand broke
138 binaries) and CLEARED func_80179B74 (1,600 sites / 523 files, three decl forms, pointer-type
only). Then it found its OWN coverage gap: it required a leading `extern`, so it reported "no
declaration found" for a TU declaring the function on line 23 without one — a silent miss that reads
exactly like "nothing to do" (R32). `extern` is now optional and PRESERVED where present.

⚠️ INSTRUMENT FAILURE, recorded: mid-session `grep <pat> <file> | head` began printing NOTHING while
exiting rc=0 (i.e. matching). Read showed the line plainly; re-done in Python the file has 3
occurrences including a CALL at line 68. It cost one wrong intermediate claim ("no extern anywhere"),
which conform_decls immediately contradicted. NO banked result is affected — every bank passed the
whole-binary byte-gate and a clean-tree R22, neither of which reads shell output. A broken diagnostic
wastes time; it cannot manufacture a match. Diagnostics moved to Python. §90a, aimed at the shell.

func_8013BD74 is NOT a wall: its byte-true def takes a draft-LOCAL struct `A`, conforming the
prototype fails `parse error before '*'` (A undeclared that early), and the prototype cannot be
deleted because a call at line 68 precedes the definition at 71. Needs the §20/§64 type-lift.
2026-07-27 12:54:00 -06:00
Drew T 1a55d1163a docs(phase-29): SESSION-21 closing checkpoint — 416 banked, 82.0% instr, next steps named 2026-07-27 11:44:45 -06:00
Drew T 7c1640888f feat(phase-29): func_8016AE5C banked + tools/conform_decls.py; a 138-binary break R22 caught
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.
2026-07-27 11:42:32 -06:00
Drew T 13812fa50c docs(phase-29): SESSION-21 T8 — span-derivation fix + func_8012AAAC 137/137; routing rule shown both ways 2026-07-27 11:26:04 -06:00
Drew T 3ef1ea08c0 docs(phase-29): SESSION-21 final checkpoint — 278 banked, jtbl chain proven, sweep blocker named 2026-07-27 10:44:40 -06:00
Drew T 1f0f33b165 docs(phase-29): name the ×137 sweep blocker — exemplar span structure does not transfer (§8e table-count drift) 2026-07-27 10:44:11 -06:00
Drew T 7c6810ba2f docs(phase-29): SESSION-21 — func_8012AAAC chain recorded; ×137 sweep 0/3 open for diagnosis 2026-07-27 10:39:35 -06:00
Drew T d3a40f2aa0 docs(phase-29): SESSION-21 checkpoint — 277 banked, wave resumable, 8 jtbl drafts ready 2026-07-27 10:08:48 -06:00
Drew T 5be4c21480 feat(phase-29): SESSION-21 — the ×138 member sweep: 274 members from 3 exemplar cracks (R22 140/140)
- 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%%").
2026-07-27 10:08:19 -06:00
Drew T 2ce6c5fade feat(phase-29): SESSION-21 — 3 family exemplars banked + the §85 return-axis widen (R22 140/140)
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.
2026-07-27 09:58:17 -06:00
Drew T 87b02b044f fix(phase-29): jtbl_carve — repair the SPLIT-TABLE undercount, gated on the function's own sltiu
THE BUG (real, found by a wave agent): jtbl_range() ends a carve at the next data dlabel, assuming
every dlabel is an object boundary. spimdisasm can CUT ONE JUMP TABLE IN HALF and emit the tail
under an invented D_ label — func_8012AAAC's 50-word table is jtbl_801D7FB0 (28) + D_801D8020 (22).
The carve then reserves 112 B for an object supplying 200 B of .rodata, shifting every later symbol.
§84-class: match_one is structurally blind; it surfaces only as a whole-binary DIFF.

THE AGENT'S EVIDENCE WAS WRONG (R14): it reported D_801D8020 as having "ZERO xrefs anywhere in the
tree" and proposed deleting the label. It has TWO (.word D_801D8020 and +0x2 in tail.data.s) —
almost certainly spimdisasm mis-symbolizing packed halfword data, but "almost certainly" is not a
gate, and the proposed remedy would have deleted a symbol two emitted words reference. I built the
xref census first, watched it refuse, and only then found the references.

THE GATE USED INSTEAD — the function's own `sltiu N` range check, which gcc emits right before the
indexed load, so the PROGRAM declares its own table length (func_8012AAAC: sltiu 0x32 = 50). Absorb
only when the next label is immediately adjacent, its words are all code addresses in the overlay's
text, and absorbing lands on an EXACT sltiu bound (the SET, not max() — a multi-switch function has
several and no way to say which owns this table).

Three further corrections, each caught by testing rather than assumed:
 - the absorption fired and the trailing-pad trim immediately UNDID it (re-trimming against the
   first dlabel's 28 words); the trim now sees the whole absorbed table;
 - a continuation ends at ITS OWN last .word, not the next dlabel (D_801D8020 ends 0x801D8078; the
   next dlabel is 0x801D8158, 224 B on) — using the next dlabel is the assumption being repaired;
 - the shortfall warning now fires only on an unambiguous single-bound pairing (it fired ~90 times
   across 38 tables before the guard — a warning that fires on ambiguity is noise, not a signal).

VERIFIED: the split table 28 -> 50 words (112 -> 200 B), matching the agent's 3 independent
confirmations; and across 38 jtbls x 6 functions = 228 combinations, EXACTLY ONE range changes —
that table, for its owning function only.
2026-07-27 09:28:08 -06:00
Drew T 181ba8c4e6 docs(phase-29): SESSION-21 wave 1 first half — 8/8 match_one MATCH, 6 of 8 blocked on ONE lever
- 8 of 24 agents completed before the session limit (16 errored on the limit, none technically);
  resumed from cache. 8 MATCH / 0 near / 0 fail, stake 210,726 templatable ins, 2.48M subagent tokens.
- CANDIDATES not banks (§58) — but DIAGNOSED ones: the prompt required symcheck + a named blocker,
  so instead of 8 opaque MATCHes there are 8 with their banking prerequisite stated.
- THE FINDING: 6 of 8 are blocked on the SAME jtbl/rodata carve class — one mechanical lever in
  front of ~153,596 templatable ins in this batch alone. Corroborated independently by
  tools/reloc_verify.py, which flagged the identical class on the drafts it could check (R34).
- A REAL jtbl_carve BUG found by an agent, confirmed 3 ways: jtbl_range() ends the carve at the
  next data dlabel, but splat split ONE 50-word table across jtbl_801D7FB0 (28) + D_801D8020 (22,
  zero xrefs) -> 112B carve for a 200B .rodata. §84-class: match_one is blind; it surfaces only as
  a whole-binary DIFF. Fix queued.
- Agents touched zero tracked files (write-set constraint held).
2026-07-27 09:21:21 -06:00
Drew T d0322d473c feat(phase-29): promote tools/reloc_verify.py — resolve every relocation before paying a gate cycle
The SESSION-20 carry item ("promote it — it closes 3 of the 4 blindness classes"), generalized:
base vram DERIVED from the target .s (was hard-coded to one function, R33) and the parse
coverage-asserted (R32 — a target that parses to zero instructions refuses to report a verdict
rather than reading "ALL RESOLVED"). Resolves jal callees, %hi/%lo data addresses (recovering the
implicit REL addend objdump -r never prints — the §84 trap) and internal j destinations.

IT TOOK TWO OF ITS OWN BUGS TO TRUST IT — both found by cross-checking masked_diff (R34):
 1. `objdump -dr` instead of `-drz`: without -z objdump ELIDES identical-instruction runs, so
    func_801330E0 read 104 ins vs masked_diff's 110 (6 elided nops) and every later index compared
    against the wrong instruction — 2 phantom mismatches on a clean draft. A comparison tool MUST
    share its reference oracle's index space exactly.
 2. the .s word field is little-endian HEX TEXT, not the instruction integer; masked_diff byte-swaps
    it and this did not — reporting "word differs" on three byte-IDENTICAL sites.

Now classifies instead of alarming: JTBL (gcc emits its own switch table via a local label => nothing
to relocate; the §81 routing signal — bank via jtbl_family_bank, never plain harvest_verify) ·
BAKED-LITERAL (same constant materialized inline: byte-correct here, but if the symbol is
per-overlay the exemplar matches and every SIBLING breaks — the §84 shape) · real mismatch.

Recorded: measuring a live wave's drafts is itself the §87 staleness error — a draft rewritten 12s
before the check gave a different verdict. Draft QA happens after the wave returns.
(The wave's gate driver lives at .run/s21_gate.py — gitignored scratch, §55b orchestration law
built in: --no-propagate per TU group, commit before the fleet propagate, and BANKED derived from
the stub set rather than read from gate_stage's accumulating verified-file.)
2026-07-27 00:06:01 -06:00
Drew T ccbc65e9c3 fix(phase-29): progress.linked_subsegs fails closed (R32) + the main-EXE bucket re-measured
- progress.linked_subsegs() was FAIL-OPEN: gated on the module global BINARY that set_binary()
  assigns, it returned an EMPTY SET when imported as a library without that call — i.e. "no
  linked library subsegs", which for main is confidently wrong (there are 49) and silently
  reclassifies ~960 already-byte-identical PsyQ-linked stubs as outstanding game-code work.
  Now raises when unconfigured; the CLI path is untouched (set_binary assigns before calling).
  Caught by hitting it myself while measuring bucket #2.
- ENDGAME-MAP CORRECTION (measured, zero-token): the map's "main EXE game code ~59,765 ins /
  ~1,048 stubs" conflates two populations. Correctly split: game code 1,042 stubs / 31,888
  measurable ins; LINKED PsyQ library 960 stubs / 27,877 ins (already byte-identical). Bucket #2
  is ~47% smaller than quoted. Caveat kept: 467 game-code stubs have NO sig row (the documented
  main second-oracle gap), so the true weight is above 31,888 and not currently measurable —
  re-price when the main second oracle lands, do not quote either number alone.
- .run/s21_zerocrack.json: the 60-family zero-crack pool enumerated (45 plain / 15 jr) and
  honestly discounted — its top entries (0x8013c414 -O0 wall, 0x80144090 LENGTH-DRIFT,
  0x80133ab0 pinned) are already-diagnosed refusals, so ~95k of the 208,499 is not available.
2026-07-26 23:41:40 -06:00
Drew T 2b38c68333 feat(phase-29): SESSION-21 T1-T3 — the frontier measured, the family-exemplar wave, 3 tool fixes
- T1 FRONTIER MEASURED (zero-token, R35: family map regenerated on fresh sigs first — it was
  stale by ~657 banked members): 36,020 stubs / 2,345,599 weighted ins remain, and only
  9.0% are h_exact-FREE. PROPAGATION IS TAPPED (238 distinct classes / 3,245 instances);
  22,498 distinct classes / 1,680,097 distinct ins is what is actually left. The mass is FLAT
  across all 139 binaries (~300-550 sub-500 stubs each) -> "pick the best overlay" is not a
  strategy. .run/s21_frontier.py + .run/s21_frontier.json
- T2 THE AXIS IS THE FAMILY, NOT THE LOCATION: 1,342 substantial h_seq families /
  1,298,135 templatable ins = 55% of ALL remaining weighted instructions. Routed by blocker:
  jr/§81 181 fams (33.6%) · DRAFT-with-cached-Ghidra-C 91 (28.6%) · DRAFT-modal 1,023 (27.5%)
  · zero-crack 45 (6.5%) · permanent walls 2 (3.9%). Live+cached+non-wall in ov_SC01_077 = 54
  families / 589,502 ins, value steeply concentrated (top 24 = 96%).
  .run/s21_targets.py + .run/s21_targets.json + .run/s21_draft_pool.json
- T3 WAVE 1 LAUNCHED: tools/workflows/family_core_wave.js (NEW) — 24 xHigh drafters, one per
  family exemplar, stake 575,488 templatable ins (24% of remaining). Supersedes worker_wave.js
  for family work: carries each target's family STAKE, encodes the four §58/§87 integration
  rules at source (splat D_<UPPERHEX> not Ghidra DAT_; never invent a symbol; canonical callee
  sigs; leave decl plumbing to the ladder), and requires symcheck.py on any claimed MATCH.
- T3b LADDER HYGIENE, both SESSION-20 carry items fixed — one defect, two masks: a byte-NEUTRAL
  transform was left in the tree when it banked nothing. family_sweep's --normalize-self-decls
  backstop only fired on MISMATCH (left 123 files of dead diff on a 0/123 run); gate_stage's
  ARITY undo narrowed to src/shared/ and left ~40 TUs. Both now restore the full snapshot when
  NOTHING banked (no banks to preserve => the splice hazard cannot apply). §61 on the success path.
- T3c BACKLOG addr DEFECT fixed (R32/R33): new addr_of() derives the address from `name`,
  assert_addr_coverage() fails loud on an unkeyable row, append_record fills both directions.
  Found a latent bug doing it: load_best() keyed on `addr or name`, splitting one function into
  two "best" records. Keyable rows 128/1,701 (7.5%) -> 1,701/1,701 (100%).
2026-07-26 23:37:35 -06:00
Drew T 2d2c01f046 docs(phase-29): SESSION-20 FINAL CHECKPOINT — behemoths done, the measured endgame map, §84-§89, the new throughput sequence 2026-07-26 23:15:28 -06:00
Drew T 454a0d2a02 docs(phase-29): SESSION-20 closing checkpoint — ~1,070 members from five tooling root causes; 81.5/69.0/89.49 2026-07-26 20:24:01 -06:00
Drew T 57e63730dc docs(phase-29): SESSION-20 final checkpoint — 395 members harvested from two tooling bugs, ~56,200 ins, zero tokens 2026-07-26 16:49:29 -06:00
Drew T c6b17f3056 docs(phase-29): SESSION-20 checkpoint — 4 causes diagnosed, 3 banked, the unlock identified but not yet harvested 2026-07-26 15:22:57 -06:00
Drew T 1d44ce25f3 docs(phase-29): CORRECTION — the T0.1 "zero-crack pool" is NOT banked (4 of 1,073 members = 0.4%)
Drew asked whether the 347,892-ins pool was banked. It was not: 4 members (func_801463A0 x2,
func_8017B490 x2) = +396 instr-weighted / +194 distinct-code, ~1 part in 900 of the prediction.

FRAMING ERROR OWNED: I labelled the pool "FREE" and "the actionable shortcut". The h_seq
classification establishes "no DRAFTING needed" (exemplar matched, members structurally identical);
it does NOT establish "no WORK needed", which is how "FREE" reads. The probe located the work:
- 2 of the 8 top families (270 members) refused BEFORE any gate by the §42e pin guard => "FREE" did
  not even imply sweepable
- of the members that reached the gate, 67% hit declaration plumbing, 0% hit compiler walls
- both plumbing keys tried FAILED (--fix-def-sig regressed; --normalize-self-decls 0/123)

Pool status: real, structurally confirmed, not gcc-blocked, still LOCKED. To bank it: find the
working key (reconcile_decls.py — the DATA-symbol analog, and one failure text WAS a DATA symbol —
or canon_sig_reconcile v3.2, both untried), then re-sweep (mechanical, zero-token), and handle the
pin-refused families via --allow-pins.

Recorded rather than quietly superseded because this pool has been mis-called in BOTH directions
(P26 dead-off-a-broken-tool, P28 same family 89%). A prediction stated as a bank is how that happens.
2026-07-26 13:29:45 -06:00
Drew T adafeb13d6 feat(phase-29): T0.3b autopsy — 44% of the "near-miss backlog" are not near-misses; 315 are plumbing-blocked MATCHes
Recomputed every backlog residual from the bytes (1,699 rows, -j 12, zero agent tokens) through the
validated match_one path, deriving asm-subdir + -O0 from corpus.py. R34 cross-check PASSED (closeness
agreed with masked_diff.structured_diff on all 1,610 built rows, 0 classifier errors); 89 nobuild rows
REPORTED not dropped (R32).

BUCKETS: redraft 707 | structural 528 | integration 315 | permuter 57 | unknown 3.

1. HONESTY CORRECTION: 707 of 1,610 (44%) are class SIZE-MISMATCH — the stored best-draft is a
   PARTIAL, an incomplete attempt logged with a closeness score (the func_80183814 666-of-5,122
   shape). docs/backlog.md has been overstating readiness by ~44%. These route to a FRESH CRACK,
   not to a wall and not to the permuter.
2. ACTIONABLE: 315 entries are match_one MATCH *right now*, blocked only on the reconcile ladder —
   recomputing beat trusting the stored label because the tree moved since they were logged.
   ~108,959 gain-ins; top func_80174CB0 (16,482), func_801463A0 (13,534). §52b still applies: ~half
   of close=0 drafts fail the whole-binary gate, so these are CANDIDATES not banks.
3. The permuter bucket is 57/1,610 = 3.5% (Task-13B measured 7.7% and called targeting the problem).
   Extending the mutation set is CONFIRMED not the big lever — small, real, now bounded.
4. R34 again: 3 of 4 comparable labels DISAGREE with measurement — func_80140D68 / func_8012A328 /
   func_801549F8 recorded "schedule" but measure ADDRESSING -> cse. The grinder was aimed wrong.

CONVERGENCE: T0.2 (8/8 failures PLUMBING, 0 walls) and T0.3b (315 integration) independently point at
the SAME lever — the declaration/integration reconcile ladder, worth the 224,410-ins FREE pool AND
~108,959 backlog gain-ins. Two keys eliminated today; untried: canon_sig_reconcile v3.2 and
reconcile_decls.py (the DATA-symbol analog — one T0.2 failure text was a DATA symbol).
2026-07-26 13:25:29 -06:00
Drew T bce8cf3248 feat(phase-29): T0.2b + T0.3 — two levers eliminated for ~0 tokens; the backlog is current but 92% unclassified
T0.2b --normalize-self-decls: CLEAN NEGATIVE 0/123 on func_8013D53C (the family whose failure text
matches the flag's own documented fix). The FREE pool's blocker is a DIFFERENT declaration class than
either tested flag — --fix-def-sig REGRESSED it, --normalize-self-decls no-ops on it. Untested next
candidates: canon_sig_reconcile v3.2 and reconcile_decls (one failure text is a DATA symbol,
"conflicting types for D_800A651C", which neither tested flag targets).

TOOL HYGIENE DEFECT: the flag's transform is byte-neutral by construction, so the non-neutral
backstop never fires and it LEFT ALL 123 EDITS IN PLACE after banking nothing (123 files / 246+ /
246-). Byte-safe but a "git add -A" trap. Reverted; spot-rebuilt ov_SC01_000 + ov_SC07_010
BYTE-IDENTICAL. Candidate fix: on a 0-bank group restore the snapshot regardless of neutrality
(§61's law applied to the success path — "neutral" is not "wanted").

T0.3 triage: 1,622 live entries, P9 filter finds 0 stale (backlog.py's drop-now-matched works).
LEDGER DEFECT (R32): the addr field is null for 1,501/1,622 (93%) — the address survives only inside
the name field, so an addr-keyed consumer silently sees 7%. My own first pass fell into it (read 121,
reported off a 7% sample); name-derivation resolves 100%. Fix flagged, not applied mid-session.
Closeness: 333 at 0, 184 at 1-4, 589 at 5-20. 1,486/1,622 (92%) UNCLASSIFIED — matching
residual_class.py's own docstring. Highest-value next: run residual_class over the unlabelled set so
the close band routes to a lever instead of grinding undirected. Zero tokens.
2026-07-26 13:16:01 -06:00
Drew T d3e6d6a702 feat(phase-29): T0.2 gate probe — the FREE pool is PLUMBING-blocked, not wall-blocked (4 banked)
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%.
2026-07-26 13:12:09 -06:00
Drew T 1fe4850136 feat(phase-29): T1.1 func_80183814 round 1 — 99.3% structural, named lever; cookbook §83
- VERIFIED INDEPENDENTLY (R14): match_one reproduces DIFF 5127 vs 5122, LENGTH-DRIFT/+5. Agent did
  not over-claim; tree untouched. Difflib-aligned truth: 36/5122 structural (99.3%), 17/21 cases
  EXACT, args+locals BYTE-EXACT at 216B
- §83a: on a LENGTH-DRIFT class match_one's mismatch count is NOT a progress signal — 4,622 and 36
  describe the same draft (index-wise comparison smears every index after the delta)
- §83b THE LEVER: the handoff's '35x repeated template' (which I passed on flagged UNVERIFIED) is
  TRUE and was the whole game — 2,625 of 5,122 ins (51%) from ONE parameterised 72-ins body. Three
  sub-levers: pointer walk (no strength-reduction under -G0), rand()%(u32) for divu, cast barrier vs combine
- §83c TRAP: the inherited 'dead local' pad[32] is gcc's OWN SPILL AREA — removing it made the locals
  area byte-exact. §83e: two 'pure allocation' residuals were a copy-pointer walk -> zero (§80 again)
- §83d THE STALL, cited: cse.c:8340 sizes the quantity table by WHOLE-FUNCTION pseudo count, so no
  per-case edit can move a function-global CSE fork. Next move = close the +5 (buys length parity AND
  perturbs max_reg), then re-run the do-not-re-buy table on the new base
- no pins in the deliverable (diagnostic-only, table row 15) — agent self-reported unprompted
- DECISION: round 2 QUEUED, not spent now — T0.2 (224,410-ins pool) outranks a ~0.04pp lever
2026-07-26 13:02:58 -06:00
Drew T 57ee715f3c feat(phase-29): T0.1 frontier survey re-run (138 ovs) — the family lever is ALIVE; a 224,410-ins zero-crack FREE pool
- verified the tool BEFORE trusting its scan (R35): load() correctly globs all 138 overlays, but the
  generated header hardcoded '134' -> fixed to derive from the same glob (a doc misreporting its own
  scope is the P28 img_path shape, one severity down)
- stale(07-23,134ov) -> fresh(07-26,138ov): fleet 88.5/79.0/68.4 -> 89.4/80.9/69.0%; families 2721 ->
  2688; substantial 558 -> 544; with-matched-sibling 74 -> 76. Structure STABLE => the P25 family
  reframe is NOT an artifact and P26's ~0% stays unsupported post-fix
- FINDING: 3,419 instances banked but only 85 distinct CLASSES fell -> recent yield was propagation,
  not new classes (SESSION-19's split, now fleet-wide)
- THE POOL: 76 zero-crack families (exemplar already matched) = 347,892 ins = 19.4% of remaining
  distinct code, decomposed by real blocker: FREE(PURE/non-jr/non-O0) 61 fams/224,410 ins = 12.5% of
  remaining; jr 13/57,311 (§81 chain); -O0 2/66,171 (known deferred build-infra, Arm A proved 9/9 bank)
- STILL A PREDICTION (R14/G3): T0.2 re-targeted from this data to measure the GATE conversion rate on
  8 members sampled across the FREE subset before any arithmetic scales
2026-07-26 12:46:34 -06:00
Drew T 4a8e8f7e36 docs(phase-29): the Drew-approved measured-order plan (T0 discovery-first) + the roadmap-to-100 gaps 2026-07-26 12:42:10 -06:00
Drew T 5873bd9cc8 docs(phase-29): record the absolute-include portability defect as a PhaseEnd carry item (Drew: handle later) 2026-07-26 12:19:08 -06:00
Drew T 661f5aa751 feat(phase-29): bank func_8017C730 x ov_SC03_013 (+1,061 ins) via the §81 carve chain
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.
2026-07-26 11:57:17 -06:00
Drew T 3b3728b19d docs(phase-29): checkpoint — an explicit START HERE NEXT SESSION block
Drew asked for the next-session recommendation to be logged. Added a ranked "START HERE" block
above the open-actions list:

1. func_8017C730 @ ov_SC03_013 FIRST (~30 min, +1,061 ins) -- the match ALREADY EXISTS; pure
   integration, no agent. Minimal preamble (bandsetup + 5 externs + 18 gte_* macros) then the §81
   carve chain. Explicitly warns NOT to re-carry the whole region file (standalone MATCH that
   fails the real gate -- the §77 corollary, measured).
2. THEN func_80183814 (5,122, the biggest left) with one Opus 5 agent @ xHigh, and an HONEST
   expectation reset: the family bonanza is over. All six behemoths banked this session were one
   renderer family with matched relatives bracketing them -- that is why 5 of 9 levers were
   readable rather than discoverable. func_80183814 has 0 fingerprint overlap and 37 callees; it
   is a different subsystem. Budget TWO passes (the func_8017BF14 shape, not the func_8017C954
   near-one-shot); a 99% round 1 is on-plan, not a stall.
3. Then func_8017D2DC (32 callees -- §71 IS usable) and func_8017DC1C (ZERO callees -- §71 CANNOT
   fire; use §79 DATA-symbol fingerprinting, shared syms only, and read a matched relative's
   fingerprint from its banked C since matched fns have no nonmatchings/*.s). A 0.00 from §71 on
   a leaf means "cannot answer", not "no relative" -- that error cost a whole agent brief today.

Also notes that behemoths were the ONLY thing that moved distinct-code this session
(+26,730 of +31,649), so they stay the lever if the queue holds.
2026-07-26 11:26:29 -06:00
Drew T cf570ec75c docs(phase-29): checkpoint — reflect §77's 5th variant now folded into the cookbook
The checkpoint said §77 'gains its 4th variant' and listed 4; the static-helper variant is the
5th and was only in the phase log until commit:1027 folded it into the cookbook proper. Both
mentions corrected so the checkpoint and the cookbook agree.
2026-07-26 11:19:29 -06:00
Drew T 22798c2809 docs(phase-29): SESSION-19 FINAL CLOSING CHECKPOINT
Fresh session safe here. No background job running; tree clean; R22 clean-fleet 140/140 (12x);
tools-health OK; 0 NON_MATCHING; dedup 1886/0. HEAD at 38 commits this session.

FLEET 80.6% instr / distinct-code 3,845,161 = 68.2% / fn-count 89.18% (opened 80.0/67.7/89.02).
+31,649 distinct-code ins: 26,730 from SIX behemoths + 4,919 from the h_norm-remap pool. Every
propagation win contributed +0 to distinct-code -- the session's most actionable finding.

Records: the banked table (11 entries incl. six behemoths and the largest match in the project,
func_8017BF14 at 4,763 ins); ten cookbook entries §73-§82 all from measurement; the through-line
(almost every cap was our own tooling or my own use of it, including four of my own claims that
collapsed under checking); six ranked open actions with named causes; six method traps that
silently return 0.00 or a false MATCH; and the measured behemoth economics (two passes at
4,700+ ins, second cheaper; reading a matched relative beat the clever lever five times).
2026-07-25 23:28:37 -06:00
Drew T 9d04c0d6df docs(phase-29): func_8017C730 @ ov_SC03_013 — standalone MATCH, not banked (§77 4th variant)
- family_remap alone: -56 LENGTH-DRIFT. §77's own text predicted the cause verbatim (a "static"
  helper is a preamble construct the extractor does not carry): the exemplar uses
  "static inline void bandsetup(...)" -- the §82-oracle-1 inlined helper -- and none was carried.
  helper + its 5 externs: -56 -> -34. Whole 2,993-line region file as preamble: MATCH (1061 ins).
- BUT the full-file carry is wrong for BANKING (my error): right for a standalone match_one
  compile, collides wholesale in the real TU. Gate -> PLUMBING, reported as "conflicting types
  for memcpy" = the §58 red-herring; the real cause needs a hand-splice + real cc1 stderr.
- NAMED NEXT STEP: minimal preamble = bandsetup + its 5 externs + the 18 gte_* macros from that
  region file, then the §81 carve chain (this sibling is ALSO a jr function). Draft preserved at
  .run/giants/s19_func_8017C730_SC03_013_nearmiss.c
- §77 gains its 4th measured variant (static helper) + a NEW COROLLARY: the right carry is the
  MINIMAL CLOSURE of what the body references, not the whole file -- over-carrying trades a
  match_one failure for an in-TU collision. Also: s19_remap_tu.py's walk-back-to-previous-brace
  heuristic breaks on an isolated region file, where the preceding construct IS the needed helper.
2026-07-25 23:27:33 -06:00
Drew T 109ce6a2c3 feat(phase-29): BEHEMOTH #6 func_8017C730 BANKED (1,061 ins) + §82 two source-shape oracles
- 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.
2026-07-25 23:24:11 -06:00
Drew T c41acdc473 docs(phase-29): record the func_8017C730 agent in the checkpoint
Opus 5 (xHigh) on func_8017C730 (1,061 ins, ov_SC03_010). Records the strongest starting signal
yet (shared-symbol set is a strict SUPERSET of the matched base func_8017CA80 -- all 6 symbols
plus exactly one extra callee func_8004974C, and 1,061 vs 952 ins => base + ~109 ins of one
feature), the five matched family exemplars bracketing it, and the §81 warning: it IS a jr
function, so match_one MATCH is not the end -- banking needs the carve chain, which is my step.
2026-07-25 22:00:52 -06:00
Drew T 0907a35cf5 docs(phase-29): reconcile checkpoint — 5 behemoths banked, +30,588 distinct-code
HEAD commit:1021, 33 commits, R22 140/140 (11x), tools-health OK. Fleet 80.6% instr;
distinct-code 3,844,100 = 68.2% (+30,588 this session: 25,669 from five behemoths + 4,919 from
the h_norm-remap pool; propagation contributed +0). func_8017C954 added to the banked table;
func_8017C730 recorded as the approved next target.
2026-07-25 21:58:28 -06:00
Drew T faf4547345 feat(phase-29): func_8017C954 BANKED — jr carve chain cleared; a shared type was PRESENT but INVISIBLE
- BANKED (1,194 ins, ×1 distinct-code). Chain cleared, each step byte-gated before the next was
  built on it: one-line fix to jr_isolate_all._engine_types() -> jr_isolate_all --only
  func_8017C954 (2 fns / 1 object, NOT the bare 47-fn / 21-object resegment) -> BYTE-IDENTICAL
  b7b0d4ae -> jtbl_carve --func func_8017C954 (44-piece carve set + interleave order) ->
  BYTE-IDENTICAL -> harvest_verify VERIFIED BYTE-IDENTICAL -> R22 clean-fleet 140/140,
  tools-health OK. instr 80.5 -> 80.6%; distinct-code 3,842,906 -> 3,844,100.
- THE DEFECT (tools/jr_isolate_all.py): _engine_types() harvested shared type names with four
  patterns -- `typedef ... X;`, `} X;`, forward-decl `struct X;`, fn-ptr typedef -- and a TAGGED
  DEFINITION WITH A BODY matches NONE of them. So `struct PW8017E6D8 { int w; }
  __attribute__((packed));` at engine_types.h:658 was present in the shared header yet invisible
  to the carried-type check, and `extern struct PW8017E6D8 D_801E1EC4;` could not be placed.
  MEASURED BLAST RADIUS: 77 such tags in engine_types.h were invisible. One added pattern fixes
  all 77.
- WHY THIS COST 20 MINUTES INSTEAD OF A MYSTERY BYTE-DIFF THREE PHASES LATER: the Phase-26 audit
  had already turned this predicate's SILENT DROP into a LOUD REFUSAL. The original bug dropped
  4,040 col-0 decls, 683 of them function PROTOTYPES -- and a dropped prototype is a SILENT
  BYTE-CHANGER (C89 implicit `int f()`; return type drives delay-slot fill in this codebase). The
  refusal named the exact symbols and the exact remedy. A loud "I cannot place this" is worth far
  more than a green build -- the audit paying for itself, live.
- §81: the 3-step jr-carve chain + why match_one CANNOT see the problem (it masks jal/HI16/LO16,
  so a jump-table function reports MATCH while the whole-binary gate reports DIFF, correctly).
  Detect with `grep -cE 'jr \$(v0|v1|a0|t[0-9])'` on the target .s + a jtbl_ in asm/<ov>/data/.
  ALWAYS use --only: bare would have resegmented 47 jr-functions across 21 objects.
2026-07-25 21:58:04 -06:00
Drew T fa51d30d3e feat(phase-29): func_8017C954 MATCHED (1,194 ins) — banking blocked on a NAMED 3-deep infra chain
- CRACKED by an Opus 5 agent @ xHigh and VERIFIED INDEPENDENTLY: match_one -> MATCH (1194 ins),
  100% every region, 1129 -> 1069 -> 37 -> 28 -> MATCH. It is the matched base func_8017CA80
  (952) + two deltas: a 14-ins grey-colour prologue from D_801DCCA0, and a FIFTH switch arm
  (case 2 / case 3 split, proved against the real jump table) emitting a POLY_FT4 plus a 7-word
  subtractive overlay.
- NOT BANKED. The whole-binary gate said DIFF and it is RIGHT: this is a jr (jump-table) function
  (jr $v0 at .s:409; table jtbl_801DB70C in asm/ov_SC06_029/data/tail21.data.s). Matching the C
  makes gcc emit that jtbl into .rodata while the raw copy stays in the data tail -> duplicate +
  wrong address. match_one masks jal/HI16/LO16 so it CANNOT see this -- the §53 carve law.
- THE CHAIN, each step failing LOUD with its own remedy (the tooling behaved well, R32/R35):
  (1) harvest_verify -> DIFF, not PLUMBING.
  (2) jtbl_carve --func func_8017C954 -> refuses: subseg ov_SC06_029_jr_8017AE2C would host
      NON-CONTIGUOUS .rodata carves (0xb3468, 0xb35b4); one object can't leave a gap for the
      unmatched jtbl between them. Remedy: isolate into its own code subseg first.
  (3) jr_isolate_all --dry-run (47 jr / 21 objects) -> REFUSES: 2 file-scope decls
      (extern struct PW8017E6D8 D_801E1EC4/EC8) could not be placed, and it will not emit a region
      that silently omits them ("a dropped prototype is a SILENT BYTE-CHANGER" -- C89 implicit
      int f(), and return type drives delay-slot fill here). NB struct PW8017E6D8 IS already in
      engine_types.h:658, so this looks like a placement-logic gap, not a missing type -- that is
      the precise next thing to check.
- => banking is a bounded BUILD-INFRA task (T2 config resegment => full R22), not more matching.
  Deliberately not started this deep into the session. Match + harness preserved and tracked.
- AGENT FINDINGS: §80(i) confirmed twice more (x_e1swap measured exactly neutral then later paid
  -2; the za lever measured worse and became necessary two levers on). NEW DIAGNOSTIC: when a
  residual is "a whole block of registers renamed by ONE SLOT", read the .greg `;; N conflicts:`
  AND `;; N preferences:` lines for the block's top allocno -- a missing hard-reg conflict plus a
  new copy preference is the signature of a one-slot slide, one dial away not forty bugs
  (c954_reg.py, the per-region scorer, is the reusable tool).
- HONEST CAVEAT (the agent's own): its lever 1 is a hand-placed byte-free __asm__ register-clobber
  dial, not a construct the original author would have typed; 14 natural spellings were tried and
  measured. Bytes unaffected, true source shape unfound; the report names the next probe.
2026-07-25 21:39:50 -06:00
Drew T 9b4b027f0e docs(phase-29): record the func_8017C954 agent + the fingerprinting method trap
Opus 5 (xHigh) on func_8017C954 (1,194 ins, ov_SC06_029); func_8017C730 queued next per Drew's
approval of successive single agents. Records why this target (1.00 SHARED-symbol fingerprint vs
the matched renderer base; 4 matched exemplars bracket it) and — importantly — the two ways I got
the fingerprint wrong before getting it right: per-overlay D_801????? names can never match across
overlays (compare only shared syms < 0x80128158), and a MATCHED function has no nonmatchings/*.s
so its fingerprint must be read from its banked C. Both mistakes silently return 0.00.
2026-07-25 20:40:57 -06:00
Drew T da5b32ac4c docs(phase-29): reconcile checkpoint — 4 behemoths banked, +29,394 distinct-code
HEAD commit:1017, 29 commits, R22 140/140 (10x), tools-health OK. Fleet 80.5% instr;
distinct-code 3,842,906 = 68.2% (+29,394 this session: 24,475 from four behemoths + 4,919 from
the h_norm-remap pool; propagation contributed +0). func_8017BF14 added to the banked table as
the largest single match in the project; its open action retired; 5 behemoths remain.
2026-07-25 20:29:34 -06:00
Drew T 8b828f1ea6 feat(phase-29): BEHEMOTH func_8017BF14 CLOSED — 45 -> 0 (4,763 ins, the largest match yet)
- 45 -> 37 -> 33 -> 21 -> 11 -> 3 -> 2 -> 0, reproduced 3x from independent work dirs. Verified
  independently before believing it (R14): match_one MATCH (4763 ins), then harvest_verify
  --binary ov_SC03_116 BYTE-IDENTICAL, then R22 clean-fleet 140 passed, 0 failed of 140.
  distinct-code 3,838,143 -> 3,842,906 = 68.1% -> 68.2%. instr 80.5%. Agent was interrupted by a
  weekly API limit and RESUMED FROM ITS TRANSCRIPT -- its round-2 harness survived, nothing was
  re-derived.
- §80 THE PROCESS CORRECTION, worth more than the match: A DO-NOT-RE-BUY ENTRY IS SCOPED TO ITS
  BASE, NOT TO THE FUNCTION. Three of round 1's ~40 measured negatives INVERTED on round 2's
  base -- the same edit (qsingle23) measured 1,040 mismatched on the 45-base and 11 on the
  21-base. Re-testing the round-1 negative list cost ~20s and produced THREE of the seven winning
  levers. Such a table records (edit, base) -> result, NOT edit -> useless; after any lever that
  moves the base materially, RE-RUN THE NEGATIVE LIST. This retroactively qualifies every
  do-not-re-buy table in the cookbook (§45, §60b, §75a, §76, §78, §79). Concrete: round 1 measured
  "removing the va->$t2 pin costs 4% elsewhere" => keep the pin; on a base with c0..c3 at function
  scope, removing those pins is worth 21->13. Same experiment, opposite conclusion.
- MY FLAGGED "#1 MOVE" LOST, and the failure is the finding. I briefed variable REUSE (§45-A /
  RC-14) as the top lever because it took func_8017F510 from 97->10. Swept in full here: EVERY
  merge lost, 43-3294 across 8 merges. Reason: the TRI and QUAD grants did not differ by RANK but
  by IDENTITY -- two independent allocno sets, and re-ranking inside one set cannot fix a two-set
  problem. Diagnose ranking-vs-identity before reaching for a merge. The actual fix (c0..c3 at
  FUNCTION scope, 33->21) was read off the two matched relatives (b5:310, b4:338) and confirmed
  against the target -- the 4th time today that reading a matched relative beat the clever lever.
- PIN'S HIDDEN COST, cited: combine_regs' hard-register branch (local-alloc.c:1795, reached from
  :1295 with already_dead==0) records the pinned reg in qty_phys_sugg UNCONDITIONALLY -- no death
  guard. A pin invites local-alloc to tie producer chains into it. New cure R7: a zero-byte
  __asm__ ref keeping the pinned value live past the temp so find_free_reg can't honour the
  suggestion -- closed the last 2 ins (c1->$a0 is uniquely load-bearing; every alternative pin
  lost 64 ins).
- §78's attribution primitive RUN and REPRODUCED: under -fno-schedule-insns, -fno-schedule-insns2
  and both, order unchanged => the rgb transposition was never a sched.c decision.
- Cold-start economics complete: round 1 = decode + exact length + exact frame + 99.06%; round 2 =
  the last 45, and cheaper. Budget TWO passes at this size. 5th source copy-paste artefact found.
2026-07-25 20:29:10 -06:00
Drew T bd768d8a4e docs(phase-29): record the func_8017BF14 round-2 agent in the checkpoint
Opus 5 (xHigh) closing the last 45/4763. Checkpoint records its deliverables, sandbox, the
round-1 residual map (a)/(b)/(c) with the measured do-not-re-buy constraints, the #1 move
(variable-REUSE sweep across c0..c3/a0v..a3v -- the one §76 lever class round 1 never swept,
and the exact merge that took func_8017F510 from 97 to 10), and the cheapest unrun probe (the
§76 attribution primitive on residual (c)).
2026-07-25 17:13:53 -06:00
Drew T f5f8dec5ee docs(phase-29): the cold-start experiment — func_8017BF14 to 45/4763; §79; full R22 discharged
- COLD-START RESULT (verified independently): 4763/4763 ins, 45 mismatched = 99.06% byte /
  99.94% structural, exact frame, exact opcode histogram. NOT a match; nothing banked (45 != 0,
  the byte-gate is the sole arbiter). The residual is 3 register-grant ties, 0 structural
  divergence. Named next move: variable REUSE across c0..c3/a0v..a3v, the one §76 lever class
  the pass never reached.
- MY BRIEF'S PREMISE WAS WRONG BY CONSTRUCTION -> §79. I chose this target partly because §71's
  callee-set fingerprint returned 0.00 against every matched giant = "a genuine cold start". But
  the function makes ZERO jal calls, so its callee fingerprint is EMPTY and §71 CANNOT FIRE:
  0.00 meant "cannot answer", not "no relative". Grepping the target's DATA symbol D_800A5E60
  found the matched func_8017BEBC at once -- func_8017BF14 is the 4-light-box member of the same
  renderer family whose 3-box sibling func_8017D960 was matched hours earlier. RULE: when §71
  returns an empty/zero-overlap callee set, fall back to DATA-symbol fingerprinting; an empty
  fingerprint must never become a cold-start brief.
- NEW LEVER (§79): THE FRAME LAYOUT IS A DECLARATION-ORDER ORACLE. gcc-2.7.2 assigns stack slots
  to spilled pseudos in pseudo-number order, and pseudo numbers follow first use ~ declaration
  order -- so the target's frame map reads back its source's declaration order. Moving ONE line
  took 73% -> 84% structural and brought all 127 slots into exact correspondence.
- §76 CONFIRMED AT SCALE: the entire -62 length residual was ONE allocno-class decision (c0..c3
  declared inside the cull blocks -> 1-death local allocnos -> global.c:668-671 removes those
  regs from the global pool -> r1lo spills), 52% -> 93%. An __asm__ ref-dial reached the same
  spill and scored WORSE -- declaration scope beat the ref dial again.
- PIN NUANCE: pins are safe on a 0-jal function (§74's hazard cannot arise), 4 pins took
  94% -> 99%; but §72 held -- pins 5 and 6 made it worse.
- EFFORT ANSWER, HONEST: xHigh from a genuine cold start on a 4,763-ins giant bought the decode,
  the exact length, the exact frame and 99.06%, and did NOT close. Budget a SECOND pass at this
  size: the first buys structure, the last ~1% is register grants.
- FULL R22 DISCHARGED: make clean + extract-all + check-all -> 140 passed, 0 failed of 140 (run
  after the agent finished, per the deferral recorded in the pool commit). tools-health OK.
2026-07-25 17:08:02 -06:00