Commit Graph

1588 Commits

Author SHA1 Message Date
Drew T b3e379faf4 feat(phase-30 S48-0b): jtbl family func_8015B950 — 1/3 blocked-binary siblings banked 2026-08-11 15:42:15 -06:00
Drew T 332ea1133c feat(phase-30 S48-0b): jtbl family func_8013FFD8 — 3/3 blocked-binary siblings banked 2026-08-11 15:41:12 -06:00
Drew T 44afe27544 feat(phase-30 S48-0b): jtbl family func_80135EB0 — 3/3 blocked-binary siblings banked 2026-08-11 15:40:54 -06:00
Drew T 7e9c6d53a4 feat(phase-30 S48-0b): jtbl family func_80159C84 — 3/3 blocked-binary siblings banked 2026-08-11 15:39:11 -06:00
Drew T 782186e598 feat(phase-30 S48-0b): jtbl family func_80131340 — 3/3 blocked-binary siblings banked 2026-08-11 15:37:38 -06:00
Drew T 9bf7c632e2 feat(phase-30 S48-0b): jtbl family func_801380E0 — 3/3 blocked-binary siblings banked 2026-08-11 15:36:47 -06:00
Drew T bb385208da feat(phase-30 S48-0b): jtbl family func_8013F350 — 3/3 blocked-binary siblings banked 2026-08-11 15:35:52 -06:00
Drew T 30f80d8a18 feat(phase-30 S48-0b): jtbl family func_8015A3C8 — 3/3 blocked-binary siblings banked 2026-08-11 15:35:04 -06:00
Drew T 374791d4be feat(phase-30 S48-0b): jtbl family func_8017A4AC — 2/3 blocked-binary siblings banked 2026-08-11 15:34:14 -06:00
Drew T f6c9867fbc feat(phase-30 S48-0b): jtbl family func_8015AE2C — 1/3 blocked-binary siblings banked 2026-08-11 15:33:32 -06:00
Drew T ec749fa584 fix(phase-30 S48-0b): JTBL_PADS follows its span through jr isolation
The 0b blocker was not "the pads line is left behind" alone — it fails two
different ways, and the second one is silent:

* bare isolate + `make build`: the stale line arms the pads filter on the
  RESIDUAL object, which emits no jump table ->
  `jtbl_rodata_pads: consumed 0 rodata .align(s) but 4 pad spec(s) given` (S47).
* isolate -> jtbl_carve (the jtbl_family_bank path): `set_pads_vars`
  regenerates the block keyed by the CURRENT subseg names, finds no prior spec
  under the new `_jr_<addr>` name, and DROPS the line. cc1's natural `.align 3`
  then pads the span's non-8-aligned interior tables and the image shifts —
  reported only as `built, bytes differ`.

- jr_isolate_all.repoint_overlays_mk: repoint the `build/src/<ov>/<sub>.o:
  JTBL_PADS` target with the `--order` leaf whenever a carve moves; refuse
  loud if the old object still hosts a .rodata piece (R32).
- jtbl_carve.set_pads_vars: second, disagreeing oracle (R34) — refuse when a
  spec would vanish for a subseg no longer in the carve set (rename/merge
  drift), instead of silently emitting a padless object.

R37 probe: func_801789AC -> ov_SC02_037 went `built, bytes differ` -> BANKED
on the whole-binary byte gate. ov_SC02_037's spec is 0,0,0,0 over tables
+0x0,+0x14,+0x34,+0x4c — load-bearing (span start is 4 mod 8).
2026-08-11 15:31:57 -06:00
Drew T 20a7cc59ee chore(phase-30 S47): FINAL session checkpoint — 2,197 banked, the residue crosses over to DIFF
2,197 instances banked, derived from the STUB ORACLE (15,542 -> 13,345), not from summing
per-batch reports (my running total said ~2,307 — summing drifts, the oracle does not).
35 commits, R22 213/213 after every batch, fleet 94.4% instr / 88.3% distinct / 96.33% fn-count.

THE STRATEGIC FINDING: the sweep residue started the session ~5:1 PLUMBING:DIFF and ends at DIFF
170 of 575 (30%), larger than the next four classes combined. The declaration-axis vein is spent;
from here the mover is volume with multipliers, not more plumbing. The Fable frontier analysis
predicted this and the residue confirmed it rather than my framing.

Landed: ~1,900 functions from plumbing at ~0 agent tokens (8 declaration axes, the symbol-KIND fix
at 205, cdFileLocTable, memcpy, the cpp-derived type map, the alias-drop fix) plus 163 from the
reach-15 agent wave at a 15x effective multiplier (reach-ordering, not the 3.55 mean, produced
that). Seven instruments repaired, cookbook to 469 sections.

Error ledger: 8, all caught. The pattern in most of them is that I proposed a mechanism before
reading evidence that was already written down — four were in files I had open.

Resume at Stage 0b (JTBL_PADS, 122 slots at ~100% measured conversion), then Stage 1's
reach-ordered sibling campaign. Stage 0a is done enough; what remains of it is bounded, not
compounding. tools-health was launched at close — confirm it before banking.
2026-08-11 14:46:29 -06:00
Drew T ce85242084 fix(phase-30 S47-0a.2): conform func_80175414 — 1,845 decls / 1,061 files; R22 213/213
The new head plumbing class after the symbol-kind fix: `conflicting types for func_80175414` (27
member-rows). Byte-true DEF is `void func_80175414(s32 _arg0)` (its DEFINE_ macro). The fleet
declared it 1,845 times in four spellings, of which three are the SAME TYPE (parameter names do not
participate) — the outlier was 28 sites declaring `(void)`.

conform_decls REFUSED the naive conform and was right to: 29 ZERO-ARG CALL SITES exist across 28
files, so conforming the declaration alone turns each into `too few arguments` — a fleet-wide
COMPILE break the per-binary gate cannot see (the tool cites 138/140 binaries, measured). It named
the count, the consequence, why the cheap check misses it, and the flag that repairs it, then
forced the two-step: --cast-zero-arg-calls (29 sites cast to the 0-arg fn-ptr shape, §17a-1 — gcc
folds the cast of a known symbol to a direct jal, so it is codegen-neutral), then the conform.

Result: 1,845 declaration sites rewritten across 1,061 files, 0 non-canonical remaining (axis
complete, R32). R22 clean-fleet: check-all 213 passed / 0 failed of 213.

WORTH RECORDING AS A TOOLCHAIN STANDARD: this is the instrument that has not wasted a cycle today.
Every other one reported SUCCESS over a defect — a classifier that discarded every gcc-2.7.2 hard
error (no `error:` prefix), a diff that miscounted 116 data-bundled .s files, a --verified-out
truncated to zero bytes over 62 real banks, a --band default that reported "0 families" on a real
135-member family, and a scope stamp describing the filesystem instead of the run. conform_decls
reports FAILURE with a repair path. A guard must state its COVERAGE, not just its verdict; the
in-repo exemplars are this tool and the §53 jr interlock.
2026-08-11 14:15:01 -06:00
Drew T fd80bd7007 feat(phase-30 S47-0a.1): the symbol-KIND fix banks 205 members; the residue crosses over to DIFF
Stage 0a's first defect, and the largest single zero-token bank of the session.

family_remap's kind test asked ONE question — is this address a function in the SIBLING'S OWN sig?
— and defaulted to `D_` on "no". But a body calls outside its image constantly: an overlay calls
resident helpers, an md_* module calls the overlay-range engine. Those addresses are absent from
the sibling's sig, so the test fell through and emitted a DATA NAME FOR A FUNCTION —
`D_800183E0`, `D_800D1EBC`, `D_80171A1C`. None exist anywhere in src/ or config/symbols.us.txt,
while `func_80171A1C` alone has 1,061 references. Measured: 611 member-rows across 45 symbols,
the largest named residue class. "Not in MY sig" means "not mine", not "is data".

Fix — three oracles, strongest first, never a blanket fallback:
 1. the sibling's own sig (authoritative for its image; this is what preserves the Phase-29 T82
    case where a slot is a function in the exemplar and DATA in the member — unioning every sig
    would have re-broken the 251 members T82 fixed),
 2. the always-linked images via extern_fn_addrs() — resident + main, 2,146 addresses whose ranges
    cannot collide with an overlay's,
 3. the exemplar reached it by `jal` — a call target is a function BY DEFINITION, which covers an
    external address neither sig claims (0x80171A1C from an md_* module, 112 rows).
Only a non-call reloc no oracle claims still falls to `D_`.

Result: BANKED 205 member-matches, failures 670 -> 575, derived net = report = 205.
R22 clean-fleet 213 passed / 0 failed of 213.
Fleet 94.4% instr / 88.3% distinct / 96.27 -> 96.33% fn-count; stubs 13,563 -> 13,345.

THE RESIDUE HAS CROSSED OVER: DIFF is now the LARGEST class at 143 of 575 — real byte divergence
outranks plumbing for the first time this session (undefined-ref 611 -> ~8, PLUMBING-other
231 -> 81). The ~5:1 plumbing:DIFF ratio that justified "tooling beats volume" has inverted in this
queue, exactly as the frontier analysis predicted: the declaration-axis vein was one-time.
The new head class is `conflicting types for func_80175414` (27) — the same addresses this fix
started naming correctly, now surfacing the NEXT layer (the symbol resolves; its declared signature
disagrees). That is the conform axis, not the remap axis.

Note for anyone auditing this class: rtu_match MASKS HI16/LO16, so a wrong %hi/%lo symbol still
reports MATCH (the T82 comment records `MATCH (10 ins)` on a member the fleet gate refused). This
defect is invisible to the per-function tool by construction — only the whole-binary gate sees it.
2026-08-11 14:02:38 -06:00
Drew T d5fbd2630f fix(phase-30 S47): family_hseq derives its own SCOPE, not just its own count; + a zero-crack glossary
The targeting oracle stamped its scope as "the N OVERLAYS only (no main, no resident)" while
load() has scanned the md_* modules and the resident since S44. Measured at this HEAD: 141 location
overlays + 70 md_* modules + the resident = 212 binaries. That is the §159 coverage law broken by
the file that documents coverage, on the repo's most load-bearing targeting instrument — and it is
how "main is structurally barren" survived two phases unexamined.

The COUNT beside it was already derived, with a comment saying "report the scope we ACTUALLY
scanned, never a hardcoded count". The PROSE describing what the count meant was hardcoded and
rotted. Both are derived now.

Caught while fixing it: my first cut read glob(".run/sig.main.jsonl") and stamped "main INCLUDED"
the moment that file existed — while load() still did not glob it. Same defect one layer down: a
stamp describing the filesystem instead of the run. Now derived from the loaded instances.

Also added a glossary line: "zero-crack" means n_matched == 0 (needs its FIRST crack) in this map,
and the OPPOSITE (a matched exemplar awaiting propagation) in roadmap §3 T3 — a ~30x mis-scope risk
for any session reading one against the other.

NOT DONE — main inclusion (0c) is still blocked on settling the attribution. Confirmed the
mechanism: main has 49 LINKED PsyQ subsegs, corpus.stubs('main') returns 2,002 INCLUDING them,
progress.py correctly excludes them and reports 1,034 game-code stubs. progress.linked_subsegs'
own docstring records this exact trap ("an importer then classifies ~1,300 already-byte-identical
LINKED library stubs as outstanding game-code work") — and my sig-main seeded from corpus.stubs,
so it inherited the LINKED rows, which is why G2's 207-family finding was inflated.
My partition probe is NOT trustworthy: 954 of 2,002 stubs returned no asm path from
corpus.asm_path, so 199 LINKED / 849 game / 954 unresolved does not reconcile with 1,034. Fix the
probe before trusting any main-scope number.
2026-08-11 13:42:40 -06:00
Drew T c0cbad1b2e docs(phase-30 S47): adopt the Fable frontier plan + the reach-ordered sibling loop
Independent frontier analysis re-derived every headline number from family_hseq.json (all reproduce
exactly) and corrected four claims, one of them mine from this session.

THE SEQUENCE: Stage 0 tooling (0a the DATA SIDE of the template engine — the 207 undefined-refs,
54/56 parse errors, 116 data-bundled .s and the F2 collisions are ONE mechanism, and unlike the
JTBL_PADS fix it COMPOUNDS across ~7,500 future member banks; 0b JTBL_PADS; 0c sig-main, recommended
yes, needs Drew; 0d a free-CPU permuter probe with a kill rule). Then Stage 1, the reach-ordered
sibling campaign to ~97.5%. Then Stage 2 singletons. Special projects LAST.

CORRECTIONS: (1) my G2 main finding was inflated — 968 of sig.main's 2,002 rows are SDK-region
stubs that fall to LINKED conversion, so the real main templating pool is ~123 families / ~303 fns
/ ~9k ins, not 207/748/11,537. (2) docs/family-hseq.md stamps its own scope as '212 OVERLAYS only
(no main, no resident)' while the map contains resident and 70 md_* modules — the §159 coverage law
violated by the file that documents coverage. (3) the close-1-4 backlog is 103, not 157, and its
reach column is TOTAL sharers not LIVE. (4) 'zero-crack' means opposite things in the roadmap and
the current map — a 30x mis-scope risk.

FRAMING: my cost-per-crack thesis holds for the singleton half only. True singleton pool is
~5,200-5,600 cracks / ~345k ins (45%); the other 55% rides on ~2,100 exemplar cracks where ORDER and
LEAK-RATE decide the calendar. Do not cross-price the two economies: 5:1 plumbing:DIFF is a property
of the residue queue, while W1's fresh wave converted 81%.

Also recorded: the 15-step reach-ordered sibling loop, with the three steps whose omission destroys
the multiplier called out (regen before targeting, regen after cracking, --band all).
2026-08-11 13:16:33 -06:00
Drew T d3f3d8ba22 feat(phase-30 S47-W1b/G2): 3 retries banked, 2 new rules; main signed for the first time
W1b — the 3 targets whose agents died on API rate limiting, retried with cookbook §160 in the
prompt: func_801EFBF4 (reach 12), func_801EFDC8 (12), func_8018CC40 (10, jr). 3/3 confirmed by an
independent verifier, all banked, R22 clean-fleet 213 passed / 0 failed of 213.

func_8018CC40 failed the first gate with `too many arguments to function func_80178970` — which its
own crack agent had PREDICTED in its report, naming the §17a-1 remedy. Dropped the draft's
empty-paren externs and cast 6 call sites instead; banked. Read the agent's integration notes
before diagnosing a gate failure — it has already seen the TU.

Cookbook §161a-c (index 469 sections):
 §161a case 0: break; is LOAD-BEARING when a jump table is indexed from zero. The natural
   case 1..5 makes gcc-2.7.2 pick minval=1, emit `addiu $v1,-1`, and shift every table index —
   58 of 77 mismatched on a byte-perfect body. Tell: the table's FIRST entry points at the
   function's own end address. Family-wide (10 members).
 §161b aliasing a parameter into a local can force a SECOND callee-saved register (+8 frame,
   +3 ins) even when uses are mutually exclusive. Suspect it before reaching for register pins.
 §161c loose-prototype engine helpers: don't fight the TU's (void) decl, cast at the call site.

G2 — THE MAIN EXPERIMENT. family_hseq excludes main as "structurally barren — zero h_exact
overlap". True and irrelevant: an h_exact claim guarding an h_seq tool. There is not even a
sig-main target — main had never been signed for this pipeline. Signed it (2,002 fns, seeded from
splat boundaries via corpus.stubs rather than --bootstrap, which glues functions around jtbl
dispatch and would have corrupted the hashes under test).

Result: main is ~85% singleton work, not 100%.
  internal h_seq families (>=2):  207 families / 748 fns / 11,537 ins (13.7%)
  shapes shared with the fleet:   161 fns / 1,346 ins (1.6%)
  genuine x1 remainder:           ~71,034 ins (84.6%)
IMMEDIATELY ACTIONABLE: 44 classes / 151 main functions / 1,239 ins already have a matched exemplar
in the fleet — free propagation, invisible only because main is not in the map.
Long-term: 748 of main's 2,002 functions (37%) are templatable once one exemplar per family is
cracked, which refutes "2,002 independent cracks" as the planning assumption for the 79k-ins tail.

OPEN, deliberately not done unilaterally: adding a sig-main target and dropping main's exclusion
from family_hseq.load() changes a fleet-shared oracle every targeting tool reads. Needs Drew's call.
2026-08-11 12:31:16 -06:00
Drew T cc3cb6e5c6 feat(phase-30 S47-W1d): jr family func_80185D70 banks 9/9 via jtbl_family_bank
The reach-10 jr exemplar cracked in the reach-15 wave; its 9 siblings needed the §53 path rather
than family_sweep (the sweep's interlock refuses has_mid_jr families by design). Per sibling:
jtbl_carve -> make extract -> remap_hseq -> make build, keep iff byte-identical.

Result: 9/9 BANKED. R22 clean-fleet: check-all 213 passed / 0 failed of 213.

WHY 100% HERE VS 56/182 THIS MORNING — the difference was never the code or the tool. This
exemplar banked RAW (so its unit is the raw crack, not an ov077-TU-specific reconciled body, which
is the trap the tool's docstring documents and which historically sent func_80178D40 to 0/4), and
every target binary was already carved. Given those two conditions the §53 path is deterministic.
This morning's 126 failures were 112 isolate-fails in three UNCARVED binaries plus 10 gate-fails
and 4 carve-fails.

Consequence for planning: the 122 jr member-slots still blocked behind the JTBL_PADS repointing in
ov_SC02_037 / ov_SC03_107 / ov_MAIN_012 are not a speculative number — they convert at the rate
just demonstrated once those binaries are carveable. Those are the same three binaries that
absorbed 1,102 of today's propagation banks, so unblocking them pays across every lane.
2026-08-11 12:22:00 -06:00
Drew T c98bb51995 chore(phase-30 S47): record the data-bundled family class — reach-57 banked, 56 siblings blocked
The reach-57 exemplar func_801EDC18 is banked and R22-green, but its family sweep returned 0/56.
54 of 56 failed 'parse error before buffer': the remapped sibling carries neither the draft's own
Blk8 typedef nor any declaration of the per-member data symbol.

Two gaps. (1) family_remap does not gather draft typedefs — the T7-S1 class, named a phase ago and
still unbuilt; cdecl.strip_provided_typedefs is NOT the culprit, it correctly keeps a typedef the
target lacks, so the loss is in unit extraction. (2) NEW: this family's data is PER-MEMBER — each
sibling's .s carries its own rodata bytes, so a symbol remap cannot produce it; the bytes must be
decoded per member and emitted as that member's definition. No existing tool does this.

Bounded: 116 of 12,583 .s files are data-bundled. The md_* module TUs cannot fall back on the
shared Blk8 (engine_types.h:497) because they include only common.h — tu_scope is 53 entries there
versus 4,190 for an overlay.
2026-08-11 12:08:43 -06:00
Drew T d806766eef feat(phase-30 S47-W1c): crack the reach-57 exemplar; fix the instrument that called it a wall
func_801EDC18 (md_SC05_023) is the largest multiplier remaining — 57 members. The wave agent
abandoned it at "closeness 6" with class SIZE-MISMATCH [redraft]. It was two lines from correct.

THE CODE (cookbook §160a): the target copies 8 bytes with lwl/lwr + swl/swr — gcc-2.7.2's
emit_block_move for a type with ALIGNMENT 1. The draft used a u32 copy (aligned lw/sw), which is
wrong by construction. `typedef struct { char c[8]; } Blk8; buffer = D_801ED98C;` reproduces it.
Six spellings were tried in parallel; two independent agents converged on the same one.

THE INSTRUMENT (§160b) — this is the part worth more than the function. The target .s bundles a
leading `.section .rodata` block (D_801ED98C as two .word) ahead of .text. Those lines carry the
same `/* off vaddr HEX */` shape as instructions, so masked_diff.insns_from_s counted them as TARGET
instructions, while insns_from_object (objdump -j .text) can never emit them. A byte-perfect draft
therefore read `mine=26, target=28, 26 mismatched` — every position shifted by a constant +2 — and
got classified as needing a redraft. 116 of 12,583 .s files in the corpus have this shape, one at
-29 instructions. Every one of them would report a false wall to any agent that tried it.
Fixed: insns_from_s tracks .section and counts only .text. Full-corpus control: 12,467 unchanged,
116 corrected, 0 regressions. Same artifact class as §129a (post-carve jtbl inflation).

THE OWNERSHIP LAW (§160c) — my own error, corrected by the gate. Four sites declare
`extern short D_801ED98C;` and nothing in src/ defines it, so I shipped an extern-only draft. The
gate refuted it: `undefined reference`. The .s block the draft REPLACED was the definition. The
variant emitting `const Blk8 D_801ED98C = {{...}}` banks clean. Never infer ownership from externs.

R22 clean-fleet: check-all 213 passed / 0 failed of 213.

ALSO BANKED — the wave's idiom harvest, which had been sitting unwritten in workflow transcripts
(R16/R30 debt): §160d the ASYMMETRIC INDEX RELOAD (a just-stored narrow field read twice emits
reuse-then-reload; the C is deliberately asymmetric), §160e a stack-layout scheduling rule now
byte-proven on a SECOND independent function (promoting it from coincidence to rule), §160f the
address-only global store via array decl, §160g sibling-search keyed on the CALLEE SET as step 0 of
every wave prompt (one grep turned a 126-instruction crack into a copy-edit).
Cookbook index regenerated: 468 sections.
2026-08-11 12:05:24 -06:00
Drew T ff11fc556c feat(phase-30 S47-W1s): the reach-15 wave templates to 140 members (81% conversion)
The 10 exemplars from W1 flipped modal -> matched in the regenerated map, so family_sweep could
template them. 9 non-jr families swept: BANKED 140 member-matches / 32 failed across 50 overlays.
Derived net = report = 140 (no untracked carve files this time, so the two counts agree).
R22 clean-fleet: check-all 213 passed / 0 failed of 213.

Fleet 94.3 -> 94.4% instr / 88.2 -> 88.3% distinct / 96.22 -> 96.27% fn-count; stubs 13,713 -> 13,563.

WAVE ONE, FULLY ACCOUNTED: 10 agent cracks + 140 templated members = 150 functions for 1.36M
tokens (~9k tokens/function). Still owed from this wave: 73 member-slots in 2 NEAR families,
34 in 3 rate-limited targets, 9 in the jr family (routes to jtbl_family_bank, §53).

TWO MEASUREMENTS THAT CORRECT MY OWN FORECASTS (R14):
 1. Conversion was 81%, not the 58% I projected from this morning's propagation run. Today's
    plumbing fixes (alias-drop, cpp-derived TU type map, group-level draft-vs-draft aliasing) are
    paying off in a population they were not tuned for.
 2. The effective multiplier was 15x, not the 2-3.5x I predicted. That estimate used the MEAN
    family size across the whole zero-crack pool (3.55); this wave deliberately targeted the TOP of
    the reach distribution, where families run 10-28 members. Ordering waves by reach is what
    produced the difference — the mean was the wrong statistic for a wave that selects on the tail.

The regen step is load-bearing and now byte-proven twice: a fresh crack reads as `modal` until sigs
+ family_hseq are rebuilt, and family_sweep templates only from `matched`. Skipping it sweeps a
stale map and the multiplier evaporates (the Phase-26 finding, whose surviving qualifier is that
remap works BEHIND a fresh crack).
2026-08-11 11:41:13 -06:00
Drew T 49f50ec7d2 feat(phase-30 S47-W1): reach-15 crack wave — 10 exemplars banked, 191 member-slots unlocked
First wave of the reach-ordered campaign: the 15 highest-reach zero-crack sibling families.
15 agents (size-routed Haiku<=30 / Sonnet 30-120 / Opus>=120), every MATCH claim re-verified by an
independent skeptic that re-ran match_one itself. 22 of 25 agents completed; 3 were rate-limited by
the API and never attempted their targets.

BANKED 10 exemplars (reach in parens), all gate-verified, R22 213 passed / 0 failed of 213:
  func_801EDC80 (28) func_801ED99C (28) func_801EDDAC (28)  md_SC05_023
  func_801EDED4 (24)  md_SC05_023        func_800CB8B4 (24)  md_MAIN_036
  func_801E8254 (14) func_801E7C04 (13)  md_SC04_025
  func_80181070 (12)  ov_SC03_024        func_8017E384 (10)  ov_SC01_005
  func_80185D70 (10, jr) ov_SC04_018 — gate auto-carved it into its own subseg (§53 machinery)

NEAR, not banked: func_801EDC18 (reach 57 — the single largest multiplier on the board) at
closeness 6, and func_8017C294 (reach 16) at closeness 2. Both are grinder/permuter candidates
rather than redraft work.
NOT ATTEMPTED (rate-limited): func_801EFBF4 (12), func_801EFDC8 (12), func_8018CC40 (10) — a clean
retry, since they never ran.

COUNTING (§55b, and the second time today this trap fired): git diff showed 12 INCLUDE_ASM removals
but only 10 are banks. func_80186460 and func_8018651C were RELOCATED into the untracked carve file
ov_SC04_018_jr_80185D70.c, not banked — verified by grepping the new file, where both still carry
INCLUDE_ASM. Any count taken across a carve must come from the stub oracle, never from git diff.

TREE SAFETY: zero agent writes to src/ or config/, despite 5 agents running while the safety
classifier was unavailable. The "drafts live in .run/ only" rule held under exactly the conditions
where it mattered.

gate_stage's --verified-out came back populated for all 6 binaries — this morning's truncation fix
(S47-C) confirmed on live traffic, not just controls.

Idioms harvested for the cookbook: the ASYMMETRIC INDEX RELOAD (a just-stored narrow field read
twice emits reuse-then-reload; the C is deliberately asymmetric — local for use #1, memory re-read
for #2), a stack-layout scheduling rule now byte-proven on a SECOND independent function
(func_8017D364 + func_801EDED4, promoting it from coincidence to rule), and a process finding:
sibling-search keyed on the CALLEE SET should be step 0 of every wave prompt — one grep turned a
126-instruction crack into a copy-edit.
2026-08-11 11:33:42 -06:00
Drew T f212ebcc28 chore(phase-30 S47): refresh frontier docs at HEAD commit:1565
Fleet 94.3% instr / 88.2% distinct / 96.22% fn-count; INCLUDE_ASM stubs 13,713.
Frontier (overlays): 6,701 families / 12,679 instances / 685,757 ins.
  siblings + matched exemplar (propagate): 166 fams / 1,122 members / 61,466 ins
  siblings + zero-crack:                 1,969 fams / 6,991 members / 342,004 ins
  singleton + matched exemplar:              53 / 53 / 4,451
  singleton + zero-crack:                 4,513 / 4,513 / 277,836
Zero-crack by size band: <30 ins 2,184 fams/89,785 ins - 30-49 1,738/118,104 -
50-199 2,353 fams/3,800 members/325,223 ins - 200-399 179/67,115 - 400+ 28/19,613.
2026-08-10 22:55:36 -06:00
Drew T 206b279ffc feat(phase-30 S47-F4): canonicalize the 2 incompatible memcpy decls (+29); the feared class was 2 lines
engine_core.h carried memcpy in 5 spellings across 9 macro-local declarations. SEVEN already agreed
in TYPE — only parameter NAMES differed, which does not conflict, and u32 IS unsigned int. Exactly
two were incompatible, and both are safe for reasons verified against the code, not assumed:

  * DEFINE_func_801325B8 declared `void memcpy()` — return type void against every draft's void*,
    which is the actual collision in ov_MAIN_012. Its only plain calls are `memcpy(dv, sv, n * 8)`
    with a VARIABLE size, which gcc cannot inline-expand, so it emits a library call under either
    prototype; the return value is discarded, so the return-type change is invisible.
  * DEFINE_func_801638A0 declared `(void *, void *, s32)` but NEVER CALLS memcpy — the body uses
    __builtin_memcpy, which is expanded directly and is unaffected by the declaration. Vestigial.

Both canonicalized to `extern void *memcpy(void *, const void *, u32);`. All 9 decls are now one
type. Gated byte-identical on ov_MAIN_012 and ov_SC03_099 BEFORE sweeping; 142 binaries instantiate
DEFINE_func_801325B8, so R22 is the real arbiter: check-all 213 passed / 0 failed of 213.

Sweep: banked +29, failures 699 -> 670.

The documented hazard (ov_MAIN_012.c:14333 — an `extern memcpy` turning an inlined block-move into
a CALL) is real but applies to a case neither macro has: a CONSTANT-size call under a
builtin-compatible prototype. The checkpoint's caution was correct; the danger just did not apply
to these two. Task B was right to defer this rather than sweep it blind.
2026-08-10 22:53:22 -06:00
Drew T 974401668f feat(phase-30 S47-F4a): cpp-derived TU type map clears the data-conflict class (+31)
scope_data_fix detected conflicts by SCANNING TU TEXT, which cannot see a MACRO-INJECTED
declaration — and that is where these conflicts live: `extern Vec8 D_80114F24;` sits inside a
DEFINE_func_* macro body in engine_core.h while the overlay .c holds only `DEFINE_func_XXXX()`.
That declaration is a genuine file-scope decl of every TU invoking the macro, and it is what the
draft collides with.

Fix: family_sweep builds a per-TU map from cdecl.tu_scope (cpp-derived, cached — 467 data decls in
ov_MAIN_012 vs 0 findable by text scan) and passes it to scope_data_fix, which now takes an
optional tu_types. tu_scope is the repo's stated oracle for "what does this TU declare", and its
own docstring warns that the `above` form answers VISIBILITY, not CONFLICT — C requires
compatibility regardless of order. scope_data_externs was built on that wrong question.

Banked 5 -> 31; failures 730 -> 699. The whole data-symbol class is gone: D_80114F24 (12),
D_800AE620 (10), D_80126B58, D_80078EB4, D_800183E0 all cleared.
R22 clean-fleet: check-all 213 passed / 0 failed of 213.

REGRESSION I CAUSED, AND FIXED: the reclassification showed 9 fresh `conflicting types for
aD800B9A02` — my own alias colliding. The group-level path suffixes the alias per function
precisely to prevent this; scope_data_externs did not, so two drafts aliasing one symbol declared
`aD800B9A02` twice with different types — re-creating the collision one level down. Both paths now
use _alias_name(sym, func). Verified: distinct names, each keeps its own type, both bind the real
symbol via the asm label.
2026-08-10 22:39:13 -06:00
Drew T 3e0028c2ed feat(phase-30 S47-F2b): group-level draft-vs-draft data aliasing (83 aliased, 5 banked)
family_sweep stages every member of an (overlay, split) group into ONE TU before gating, so two
templated bodies routinely carry different views of one address — D_80114F24 is `s32` in one body
and `Vec8` in another. scope_data_fix is handed one draft plus the pre-splice TU and structurally
cannot see the others, so that collision was invisible to it.

_alias_group_data_conflicts(): after staging, any data symbol a group's drafts declare with >=2
distinct types gets a PER-DRAFT §37 asm-label alias. The alias is suffixed with the function name
(aD80114F24_8017B880) — aliasing both drafts to a shared name would re-create the same collision at
one remove, which the unit test exists to catch. Each body keeps its own type: for data the declared
type drives the load (lh vs lhu), so canonicalising would silently change codegen for every other
view. Codegen unchanged — the asm label pins the emitted symbol.

83 conflicts aliased across 172 groups; banked 2 -> 5. R22 clean-fleet 213 passed / 0 failed of 213.

WHY THE HEADLINE SYMBOLS DID NOT MOVE — root cause now CONFIRMED, not inferred. D_80114F24 (12)
and D_800AE620 (10) are unchanged because the conflicting declaration is MACRO-INJECTED:
`extern Vec8 D_80114F24;` lives inside a DEFINE_ macro in engine_core.h (D_800AE620 has 6 such),
while the overlay .c holds only DEFINE_func_XXXX() invocations. Neither a scan of the staged drafts
nor a scan of the TU text can see it — that needs the preprocessed TU. The sweep already does
exactly this for CALLEES (cast_call_sites' canonical map is cpp-derived "so it sees macro-injected
declarations"); the data path never got it.

This collapses F2's remainder and F4 into one fix: memcpy's 26 failures are the same shape — task B
found nine `extern void *memcpy(...)` spellings inside those same DEFINE_ macros. A cpp-derived
declaration map feeds both, and the alias mechanism is already built and control-tested; only the
detection SOURCE is wrong. For memcpy the alias is the documented house solution, not a workaround
(engine_core.h:24480 hand-writes `extern void func_8005C324(...) __asm__("memcpy")`).

Four attempts on this class for 5 members: three mechanisms proposed before reading what the
compiler actually complained about. The mechanisms are correct; they targeted the wrong collision.
2026-08-10 22:24:13 -06:00
Drew T d4d35ec738 feat(phase-30 S47-F2): auto-alias conflicting data externs (partial: 2/44); real cause recorded
The 44 data-symbol conflicting-types failures are NOT the cdFileLocTable duplicate-typedef class.
They are genuine per-view type differences: D_80078EB4 is s16 at 2,409 sites and u16 at 1,341;
D_800AE620 is Blk20/s32/Mat32. For data the declared type drives the load (lh vs lhu), so
canonicalising would rewrite thousands of already-banked sites' codegen. The answer is one type
PER VIEW — the §37 asm-label alias the fleet already hand-writes for D_800AE620 (9 sites).

Shipped: scope_data_externs now auto-aliases a conflicting extern —
    extern s16 aD80078EB4 __asm__("D_80078EB4");
keeping the draft's own type (byte-truth for that body) while the private C name makes collision
impossible and the asm label pins the emitted symbol, so codegen is unchanged. Fires only where
the TU declares that symbol with a DIFFERENT type text; same-type and already-aliased drafts are
untouched (4 controls, 2 of them negative). Applied on both scope paths — a staged draft's externs
arrive indented, so a demote-path-only fix reached 1 of 44.

R22 clean-fleet: check-all 213 passed / 0 failed of 213.

WHY ONLY 2 BANKED — the collision is DRAFT-vs-DRAFT, not draft-vs-TU. The failing draft declares
`extern s32 D_80114F24;` and ov_MAIN_012.c declares that symbol nowhere; the error lands at the
splice point. family_sweep stages every member of an (overlay, split) group into one TU before
gating, so two templated bodies with different views of one symbol collide with each other.
scope_data_fix sees one draft plus the pre-splice TU and structurally cannot see the others.
The real fix belongs in the staging loop, which knows the whole group: alias any data symbol
declared with >=2 distinct types across the drafts staged together. Not attempted here.

Three wrong inferences on this one task before reading a failing draft: scoped as the typedef
class; aliased only the demote path against the file's own comment; targeted the wrong collision.
2026-08-10 21:56:31 -06:00
Drew T b9033851cf fix(phase-30 S47-F1): classify diagnostics by position, not vocabulary — 93 unknowns all named
harvest_verify.classify_fail kept only stderr lines containing the word `error`. gcc-2.7.2 emits
no `error:` prefix on hard errors, so lines like

    src/…/ov_SC02_037_jr_8013B83C.c:447: multiple storage classes in declaration of `tail_…'
    src/…/ov_SC06_025_jr_8012ACE0.c:2217: `tbl_D_80187044' undeclared (first use this function)

never survived the filter, `errs` held nothing but make's `Error 33` wrapper, and every hard error
was labelled CC1-FAIL(no-diagnostic) — "the compiler failed and we cannot see why". Measured cost
this session: 132 siblings of func_80132018 classified that way by one missing declaration, which
reads as a codegen wall and gets a family deprioritised. rtu_match had the same blindness repaired
at T0(b); the fix was never propagated here.

Fix: a diagnostic is a POSITION, not a vocabulary — `<file>:<line>: <text>`, plus the assembler's
`{standard input}:<line>:` (_SRC_DIAG). Context lines carry no `:<line>:` and are skipped.
Five controls pass, including the two that guard against over-fixing: PLUMBING still wins on a
declaration conflict, and a warnings-only failure still returns no-diagnostic.

Re-swept: 0 no-diagnostic remain. The 93 resolve to 35 redefinition-note, 11 D_801202A0
undeclared, 10 too-many-arguments, 4 too-few-arguments, 4 func_8001534C undeclared — every one a
cheap declaration/arity class, not a wall.

Residue now fully named (737): 207 undefined-reference across 42 symbols (a link-stage REMAP gap,
now the largest class), 138 DIFF (real divergence, 19% — the honest floor), 44 data-symbol
conflicting-types, 35 redefinition-note, 26 memcpy, 24 redeclared, 15 undeclared, 14 arity.
2026-08-10 21:28:00 -06:00
Drew T dbed0942b1 feat(phase-30 S47-A4): cdFileLocTable typedef alias banks 138 members; R22 213/213
The one-line fix committed ahead of this run (CdFileLoc_80128C98 aliasing CdFileLoc) cleared the
largest remaining propagation-sweep class. Re-sweep: 138 member-matches banked, failures 875 -> 737,
`conflicting types for cdFileLocTable` gone entirely (136 -> 0).

Derived net (138 INCLUDE_ASM removed, 0 re-added) equals the report's 138 — they agree.
R22 clean-fleet: check-all 213 passed / 0 failed of 213.
Fleet 94.2 -> 94.3% instr / 87.9 -> 88.1% distinct / 96.15 -> 96.21% fn-count; stubs 13,780.

Residue reclassified — no symbol dominates any more: 227 PLUMBING-other, 125 DIFF (real byte
divergence, 17%), 93 CC1-FAIL(no-diagnostic), 26 memcpy, then a tail of small data-symbol
conflicts (D_80114F24 12, D_800AE620 11, D_800183E0 9, D_80126B58 6, D_80078EB4 6).

CC1-FAIL rose 77 -> 93 and that is NOT a regression: members that previously died earlier on the
cdFileLocTable conflict now reach a different compile error. Those 93 are hard gcc errors whose
text the sweep's classifier discards because it greps for `error:`, which gcc-2.7.2 never emits on
hard errors. That classifier is now the highest-value instrument fix left — three times today a
no-diagnostic verdict concealed something cheap.
2026-08-10 20:59:06 -06:00
Drew T 320a14921c fix(phase-30 S47): CdFileLoc_80128C98 aliases CdFileLoc — clears 136 sweep conflicts
`conflicting types for cdFileLocTable` was the single largest remaining propagation-sweep failure
class (136 of 875). Cause: engine_types.h defined the SAME layout twice —

    typedef struct { s32 word0; s32 word4; } CdFileLoc;
    typedef struct { s32 word0; s32 word4; } CdFileLoc_80128C98;

Each anonymous struct definition mints a DISTINCT C type, so a TU holding both
`extern CdFileLoc_80128C98 cdFileLocTable[]` (137 sites) and `extern CdFileLoc cdFileLocTable[]`
(9 sites) is declaring one object with two incompatible types. This is the same type-IDENTITY
collision scope_data_externs documents for S_AF634: no type-STRING compare can see it, and
cdecl.compatible correctly answers "compatible".

Fix is one line — `typedef CdFileLoc CdFileLoc_80128C98;` — so the two NAMES denote one type.
Byte-neutral by construction: identical layout, so indexing scales by the same 8 bytes either way.

NOT unified with the 3 `extern u8 cdFileLocTable[]` sites: element size drives index scaling and
those sites carry their own explicit `<< 3` (note at resident.c:656). Folding them in would change
codegen, which is exactly the memcpy-class trap.

Verified byte-identical on ov_SC01_077 and ov_SC03_099. Committed ahead of the re-sweep so the
sweep's per-member revert cannot undo it mid-run; fleet R22 lands with the sweep batch.
2026-08-10 20:36:33 -06:00
Drew T 713b093845 fix(phase-30 S47): three splitter defects blocking the monolithic-overlay carve
Found while scoping the jr carve for the 3 newly-onboarded binaries. My scoping said "one
unplaceable construct" — it was the first of four layers. Three are fixed here; the fourth is out
of this tool's scope and leaves the carve blocked.

1. asm_label_aliases: the scan could START inside a #define. `#define gte_SetRotMatrix(r0)
   __asm__ volatile ("lw $12, 0( %0 );" ...)` is textually `ident(...) __asm__(...)`, and
   cdecl._mask blanks string CONTENT — deleting the `;`s that would stop the greedy [^;{}]*.
   The match ran 116 lines and swallowed the real `aF8012EFB8 ... __asm__("func_8012EFB8");`,
   so the alias never entered the map and addr_of returned None. jr_isolate_all then refused to
   carve (R32, correctly), which presented as 112 isolate-fails that looked like a per-binary wall.
   Fixed: _mask_cpp_directives() — a preprocessor directive is the other place a match must not
   start. Masking comments/strings fixed the comment case and left this one.

2. _split_macro_body returned a `static inline` internal HELPER as the macro's definition, so
   _proto_from_lines hoisted `extern static inline void tail_8012F274(...);` into all 41 regions:
   invalid C (multiple storage classes) AND the wrong function — the exported definition sits
   below the helper and lost its implied declaration. Fixed: skip static definitions
   brace-balanced on the masked body. A static helper needs no hoisted declaration at all.

3. A declaration that WRAPS across continuation lines was taken as one line, so half became a
   `;`-less extern and the continuation was read as the definition header, producing
   `extern __asm__(""); void aF801466F0(...);` in 22 regions. Fixed: accumulate until the
   statement terminates, tested on the masked text. Same wrapped-declaration blindness
   family_remap._alias_decl_for records fixing at S33 — never propagated here (§134/§139).

Not fixed, and why: jtbl_rodata_pads reports "consumed 0 rodata .align(s) but 4 pad spec(s) given
— table-count drift vs the carve". The carve moves jtbl-owning functions into _jr_ regions but
leaves the pad specs on the residual gap object. jr_isolate_all's docstring states this class is
NOT isolate-fixable; it needs JTBL_PADS repointing in overlays.mk. 122 jr member-slots stay blocked.

Regression-checked: 1,948 macros parse with 0 malformed externs; alias maps unchanged on three
already-carved overlays. No build impact (splitters run offline). Carve reverted, tree clean.
2026-08-10 20:08:53 -06:00
Drew T ba04cc3e0b feat(phase-30 S47-A3): jtbl family func_80180B64 — 2/2 siblings banked
Exemplar ov_SC01_077 @0x80180b64 (matched-ov077), 2 members. Per-sibling whole-binary byte-gate (G3/P9) is the
arbiter: jtbl_carve -> make extract -> remap_hseq -> make build, keep iff byte-identical else
revert. Tally: === func_80180B64: {'BANKED': 2} ===

Committed per family because jtbl_family_bank's per-sibling revert restores from HEAD — an
uncommitted prior family would be lost. Campaign-end R22 verifies the fleet.
2026-08-10 19:35:11 -06:00
Drew T ab9d2f48d5 feat(phase-30 S47-A3): jtbl family func_80183BAC — 5/5 siblings banked
Exemplar ov_SC01_077 @0x80183bac (matched-ov077), 5 members. Per-sibling whole-binary byte-gate (G3/P9) is the
arbiter: jtbl_carve -> make extract -> remap_hseq -> make build, keep iff byte-identical else
revert. Tally: === func_80183BAC: {'BANKED': 5} ===

Committed per family because jtbl_family_bank's per-sibling revert restores from HEAD — an
uncommitted prior family would be lost. Campaign-end R22 verifies the fleet.
2026-08-10 19:32:29 -06:00
Drew T 80459b7720 feat(phase-30 S47-A3): jtbl family func_801789AC — 2/3 siblings banked
Exemplar ov_SC01_077 @0x801789ac (matched-ov077), 3 members. Per-sibling whole-binary byte-gate (G3/P9) is the
arbiter: jtbl_carve -> make extract -> remap_hseq -> make build, keep iff byte-identical else
revert. Tally: === func_801789AC: {'BANKED': 2, 'isolate-fail': 1} ===

Committed per family because jtbl_family_bank's per-sibling revert restores from HEAD — an
uncommitted prior family would be lost. Campaign-end R22 verifies the fleet.
2026-08-10 19:30:02 -06:00
Drew T 4d84052723 feat(phase-30 S47-A3): jtbl family func_8017FEE0 — 1/1 siblings banked
Exemplar ov_SC02_026 @0x8017fee0 (matched), 1 members. Per-sibling whole-binary byte-gate (G3/P9) is the
arbiter: jtbl_carve -> make extract -> remap_hseq -> make build, keep iff byte-identical else
revert. Tally: === func_8017FEE0: {'BANKED': 1} ===

Committed per family because jtbl_family_bank's per-sibling revert restores from HEAD — an
uncommitted prior family would be lost. Campaign-end R22 verifies the fleet.
2026-08-10 19:29:35 -06:00
Drew T 850db32dfc feat(phase-30 S47-A3): jtbl family func_80179B74 — 2/3 siblings banked
Exemplar ov_SC01_077 @0x80179b74 (matched-ov077), 3 members. Per-sibling whole-binary byte-gate (G3/P9) is the
arbiter: jtbl_carve -> make extract -> remap_hseq -> make build, keep iff byte-identical else
revert. Tally: === func_80179B74: {'BANKED': 2, 'isolate-fail': 1} ===

Committed per family because jtbl_family_bank's per-sibling revert restores from HEAD — an
uncommitted prior family would be lost. Campaign-end R22 verifies the fleet.
2026-08-10 19:27:29 -06:00
Drew T 1358cc7075 feat(phase-30 S47-A3): jtbl family func_8017AE2C — 1/3 siblings banked
Exemplar ov_SC01_077 @0x8017ae2c (matched-ov077), 3 members. Per-sibling whole-binary byte-gate (G3/P9) is the
arbiter: jtbl_carve -> make extract -> remap_hseq -> make build, keep iff byte-identical else
revert. Tally: === func_8017AE2C: {'isolate-fail': 2, 'BANKED': 1} ===

Committed per family because jtbl_family_bank's per-sibling revert restores from HEAD — an
uncommitted prior family would be lost. Campaign-end R22 verifies the fleet.
2026-08-10 19:19:23 -06:00
Drew T 0a5ee2de7d feat(phase-30 S47-A3): jtbl family func_80184C74 — 3/3 siblings banked
Exemplar ov_SC06_018 @0x80184c74 (matched), 3 members. Per-sibling whole-binary byte-gate (G3/P9) is the
arbiter: jtbl_carve -> make extract -> remap_hseq -> make build, keep iff byte-identical else
revert. Tally: === func_80184C74: {'BANKED': 3} ===

Committed per family because jtbl_family_bank's per-sibling revert restores from HEAD — an
uncommitted prior family would be lost. Campaign-end R22 verifies the fleet.
2026-08-10 19:14:37 -06:00
Drew T 4878432f0c feat(phase-30 S47-A3): jtbl family func_80180B04 — 2/5 siblings banked
Exemplar ov_SC06_020 @0x80180b04 (matched), 5 members. Per-sibling whole-binary byte-gate (G3/P9) is the
arbiter: jtbl_carve -> make extract -> remap_hseq -> make build, keep iff byte-identical else
revert. Tally: === func_80180B04: {'gate-fail': 3, 'BANKED': 2} ===

Committed per family because jtbl_family_bank's per-sibling revert restores from HEAD — an
uncommitted prior family would be lost. Campaign-end R22 verifies the fleet.
2026-08-10 19:11:20 -06:00
Drew T 0a5be43765 feat(phase-30 S47-A3): jtbl family func_801884D8 — 15/15 siblings banked
Exemplar ov_SC02_028 @0x801884d8 (matched), 15 members. Per-sibling whole-binary byte-gate (G3/P9) is the
arbiter: jtbl_carve -> make extract -> remap_hseq -> make build, keep iff byte-identical else
revert. Tally: === func_801884D8: {'BANKED': 15} ===

Committed per family because jtbl_family_bank's per-sibling revert restores from HEAD — an
uncommitted prior family would be lost. Campaign-end R22 verifies the fleet.
2026-08-10 19:03:17 -06:00
Drew T 7adaddd0c9 feat(phase-30 S47-A3): jtbl family func_80178D40 — 2/3 siblings banked
Exemplar ov_SC01_077 @0x80178d40 (matched-ov077), 3 members. Per-sibling whole-binary byte-gate (G3/P9) is the
arbiter: jtbl_carve -> make extract -> remap_hseq -> make build, keep iff byte-identical else
revert. Tally: === func_80178D40: {'BANKED': 2, 'isolate-fail': 1} ===

Committed per family because jtbl_family_bank's per-sibling revert restores from HEAD — an
uncommitted prior family would be lost. Campaign-end R22 verifies the fleet.
2026-08-10 19:00:27 -06:00
Drew T f68188a73c feat(phase-30 S47-A3): jtbl family func_8018A564 — 21/22 siblings banked
Exemplar ov_SC02_027 @0x8018A564 (matched), 22 members, 125 ins each. Per-sibling whole-binary
byte-gate (G3/P9) is the arbiter: jtbl_carve -> make extract -> remap_hseq -> make build, keep iff
byte-identical else revert. Tally: {'BANKED': 21, 'isolate-fail': 1}.

Committed per family because jtbl_family_bank's per-sibling revert restores from HEAD — an
uncommitted prior family would be silently destroyed mid-sweep (the tool refuses a dirty tree for
this reason). Campaign-end R22 verifies the fleet.

NOTE on counting: the jtbl carve creates NEW split files, so a git-diff INCLUDE_ASM tally
over-reports (removals visible, re-additions inside untracked files not). True count settles
against the stub oracle at the campaign-end R22.
2026-08-10 18:59:45 -06:00
Drew T efec1b9b71 fix(phase-30 S47-A1): asm-label aliases must never be dropped by §8d; +148 members
scope_data_externs §8d drops the draft's decl of any symbol the TU already declares at file scope.
It keys on the SYMBOL, but a §37 asm-label ALIAS binds a DIFFERENT C identifier to that symbol:
the TU declares `D_801851BC`, it does NOT declare `tbl_D_80187044`. Dropping the alias left the
body referencing an undeclared name, which cc1 reports with no `error:` prefix — so the sweep
classified all 132 siblings as CC1-FAIL(no-diagnostic), i.e. as a codegen wall.

The bitter part: the alias exists PRECISELY BECAUSE the TU declares that symbol with a conflicting
type (a `void (*[])(void)` dispatch table vs this function's 20-byte-stride view). The drop rule
fired on exactly the declarations written to survive it. Why 1 of 2 died was fully determined:
tbl_D_80187048's symbol is not in the TU, so it demoted normally.

Fix: is_asm_alias() — an alias is demoted into the body, never dropped (the identifiers differ, so
it cannot collide with the TU's decl). Control-tested 6 ways incl. self-labels and plain externs.

Measured: func_80132018 3/135 -> 135/135; full re-sweep +16 more. Total +148 members.
R22 clean-fleet 213 passed / 0 failed of 213. tools-health OK, dedup-check 1949/0.
Fleet 96.11 -> 96.15% fn-count, 87.8 -> 87.9% distinct; stubs 14,120 -> 13,972 = -148 (2nd oracle).

CORRECTION TO MY OWN CLAIM (R14): after the probe I said the 58% aggregate was concealing a broad
problem. The re-sweep refuted it — only 16 more banks fleet-wide. The alias class really was one
family; the first read ("outlier") was right and the correction was wrong.

875 sweep failures classified: 231 PLUMBING-other, 141 DIFF (real divergence, only 16%),
136 `conflicting types for cdFileLocTable` (ONE symbol — biggest single class left),
77 CC1-FAIL(no-diagnostic), 26 memcpy, 12 D_80114F24, 11 D_800AE620, 9 D_800183E0.

STILL UNFIXED, and the most dangerous instrument left: the sweep's failure classifier greps for
`error:`, which gcc-2.7.2 never emits on hard errors. Every hard error therefore reads
CC1-FAIL(no-diagnostic). That is how a missing declaration looked like a codegen wall across 132
functions. rtu_match was fixed for this at T0(b); this classifier was not.
2026-08-10 18:50:48 -06:00
Drew T 57e345fcce feat(phase-30 S47-P): propagation sweep banks 1,419 member-matches for ~0 agent tokens
family_sweep --hseq --band all -j 8 over every matched-exemplar family: 553 families /
203 overlays / 1,419 banked / 1,023 failed (58%). R22 clean-fleet 213 passed / 0 failed of 213.
tools-health OK, dedup-check 1949 validated / 0 failed.

Fleet: 93.9 -> 94.2% instr / 87.2 -> 87.8% distinct / 95.72 -> 96.11% fn-count.
Second oracle (R34): INCLUDE_ASM stubs 15,542 -> 14,120 = -1,422, equal to the diff-derived net
(1,451 removed - 29 re-added = 1,422 = 1,419 sweep + 3 probe). Three independent counts agree.

B -> C -> P IS ONE CHAIN, NOT THREE WINS. 1,102 of the 1,422 landed in ov_SC02_037 (409),
ov_SC03_107 (364), ov_MAIN_012 (329) — the three newly-onboarded binaries from C, which had never
been wired into the shared-body ecosystem, so every matched exemplar was unreachable from them.
B fixed the declarations, C wired the include, P poured through the opening. A repeat sweep will
NOT pay like this; the opening was one-time.

S47 total: 1,481 functions banked with zero agent drafting, all from removing plumbing.

Two findings recorded, neither fixed (deliberate, costed):
- --band defaults to `substantial`: the first probe returned a confident {"families": 0,
  "banked": 0} on a real 135-member `mid` family. Always pass --band all.
- The alias-gather defect: probe on 0x80132018 banked 3/135, all 132 failures classified
  CC1-FAIL(no-diagnostic) because gcc-2.7.2 emits no `error:` prefix. Real error is
  `tbl_D_80187044' undeclared` — the exemplar declares TWO §37 asm-label aliases and uses both,
  family_remap carried one. T7-S1's "gather" class. Measured as an OUTLIER (aggregate 58%),
  which is why the sweep ran before the fix.

Refused by design, all named: 50 jr families / 183 member-slots (§53 interlock — it printed its
own coverage and reason), 264 STRUCT, 112 unresolved immediates, 3 not-stub.
2026-08-10 17:59:35 -06:00
Drew T 5f001a9392 chore(phase-30 S47): refresh derived frontier docs at HEAD commit:1543
Regenerated after the S47-B/C banks (family_hseq.py + report): docs/family-hseq.md,
docs/progress.fleet.md, docs/backlog.md. Numbers only — no analysis change.

Frontier at this HEAD (overlays only): 7,085 families / 14,508 instances / 752,073 ins.
  with siblings (>=2): 2,429 fams / 9,852 members / 467,634 ins (62.2%)
    - matched exemplar (propagate, ~0 tok): 460 fams / 2,861 members / 125,630 ins
    - zero-crack (crack 1 -> templates to N): 1,969 fams / 6,991 members / 342,004 ins
  singletons: 4,656 fams / 4,656 members / 284,439 ins (37.8%)
    - matched exemplar: 143 / 6,603 ins   - zero-crack (pays x1): 4,513 / 277,836 ins

Structural: the x138 era is over — 3 fleet-wide families remain and ALL 3 already have matched
exemplars, so no fleet-wide CRACK is left, only propagation. 82% of remaining code now sits in
the two worst cost profiles (x2-9 zero-crack 45.5%, singleton zero-crack 36.9%).
2026-08-10 16:48:49 -06:00
Drew T e92ba14028 feat(phase-30 S47-C): dedup_extend banks 62/129 (first non-zero); gate_stage verified-out fix
C, unblocked by B's declaration conform. 23/23/16 banked across ov_SC03_107, ov_MAIN_012,
ov_SC02_037 — the first non-zero result on this population (S46 got 0/142, then 0/129).
R22 clean-fleet: check-all 213 passed / 0 failed of 213. tools-health OK.
dedup-check 1949 validated / 0 failed, C1 coverage 249295 (= 249233 + 62, independent
confirmation of the count). Fleet 93.9% instr / 87.2% distinct / 95.72% fn-count.

THE TOOL REPORTED "BANKED 0 / 129" AND WAS WRONG. gate_stage's ladder hands the same
--verified-out path to harvest_verify on every rung, and each rung opens it for write: stage 0
banked 23 and wrote them, then a later rung that banked nothing truncated the file to 1 byte.
The in-memory list uses += and stayed correct, which is why the JSON verdict listed all 23 names
while the file said nothing. dedup_extend read the file, printed BANKED 0, and took its
`if not banked:` branch — skipping add_members_surgical, so the registry was missing 62
memberships for functions already spliced in and byte-verified.

- Registry repaired by deriving the banked set from git diff (+DEFINE_func_*), not from the
  broken file. Post-check: 0 missing.
- ensure_include_revert did NOT fire (added_include False, include already present) — the
  P29-S19 defect that once stripped a load-bearing include from 135 binaries stayed closed.
- gate_stage now writes verified_out once at the end from the accumulated truth.

Caught only because bank truth is derived from source (§55b), never from the gate report.
Residue (67) is consistent with the symbols B deliberately left: memcpy 17, ApplyMatrixSV 12,
gte_SetRotMatrix 4, plus 21 CC1-FAIL and 3 DIFF. Not separated: how much of the 62 is B's
conform vs the ladder's own recovery rungs.
2026-08-10 16:35:57 -06:00
Drew T 9ab9120e04 feat(phase-30 S47-B): conform 8 declaration axes (~10,930 sites); 3 guard defects fixed; 213/213
Task B, re-scoped from evidence. The 129 dedup_extend failures are 106 conflicting-types /
21 CC1-FAIL / 4 undefined-ref / 3 DIFF — real byte divergence is 2%, and memcpy is 17 of 106,
not the story. Direction reversed too: the byte-true DEF of func_80128ED8 is what the target
.c files already declare; engine_core.h's macro-local extern was the stub-era guess.

Conformed 8 axes to byte-truth (func_8012F14C 2843, func_8012E5CC 2052, func_8012F038 2214,
func_8014C568 1816, func_80128ED8 1524, func_8012C750 406, func_8012C0EC 50, func_80144A04 25).
R22 clean-fleet: check-all 213 passed / 0 failed of 213. Zero functions banked by design.

Tooling (R33/R35) — three guards that asserted completeness over a narrowed population:
- NEW tools/macro_draft.py: a deduped fn has no definition in any .c (body lives in a DEFINE_
  macro), so conform_decls had been refusing the largest class it was built for.
- conform_decls skipped engine_core.h wholesale as "a defining TU": 10 stale externs survived
  while 1,514 fleet sites moved, and it still printed "axis complete". Skip now scoped to the
  defining macro's span.
- Return-axis compare was literal: typedef int/s32 and a missing `extern` faked a return change.
  Now compares normalized types.
- §85 consumer scan under-reported (the dangerous direction): a cast between `=` and the call
  hid `s0 = (s32 *)func_80144A04(...)`. Now classified by position, validated both ways.

Corrections to my own predictions (R14): the documented scalar-narrowing hazard was benign
across 2,052 sites; the breaks were arity (6 call sites, fixed with §17a-1 fn-ptr casts) and
the consumer-guard gap. A header-only first probe broke ov_SC01_000 — §85 is literal.

Not done, named: memcpy (builtin codegen), ApplyMatrixSV (no DEF), gte_SetRotMatrix (link bug),
func_80147364 (unparseable macro), D_800AE620/D_80126CC4 (data axis). Cookbook §159.
2026-08-10 16:01:49 -06:00
Drew T b0c1e14fda feat(phase-30 S46-final): 400+ cascade banked (11) + waste-prevention gate; B re-scoped, C blocked
- BANKED: 11 functions at 400-952 ins from the cascade (func_8017D898 952, func_8017CE58 733,
  func_801902EC 673, func_8018C2D8 673, func_8018A8D4, func_8017C6F4, func_800CBB38,
  func_800CF3A4, +3). check-all 213/213 from a clean tree. 6 near = jr/switch (§53 separate
  banking step), 1 failed. The cascade agents wrote 6 new cookbook sections incl. §158.
  ⚠️ tools-health UNVERIFIED at commit (stale cookbook index fixed, confirming re-run
  interrupted) — run it first next session. check-all is the byte oracle and it is green.
- WASTE PREVENTION (Drew: "prevent this from ever happening again, however you need to"):
  * tools/validate_targets.py (NEW) — names 5 defect classes (NO-ASM / MID-BODY /
    OUT-OF-RANGE / ALREADY-DONE / NO-BOUNDARY), exits non-zero.
  * WIRED INTO wave_snapshot so it fails closed — every wave passes through there for its .s
    files, so no path from target list to spawned agents bypasses validation. Negative-control:
    a 3-target bad list is refused with the exact mid-body offset (+72 bytes of 100).
  * The cascade `done()` predicate now short-circuits on SKIPPED as well as MATCH. It tested
    only MATCH, so a non-existent target fell Sonnet -> Opus -> Fable and three agents each
    proved the same phantom absent: ~29 invalid targets x 3 tiers = 87 of 119 agents, ~9.7M
    tokens. A tier that cannot act must END the pipeline, not escalate emptiness.
  * docs/accelerators.md A9, including that wave_snapshot's own R32 assertion REFUSED that list
    (24 of 57 found) and was routed around — the one instrument warning that was right and ignored.
- B RE-SCOPED (S46-10) and deliberately NOT done: the extend blocker is INTRA-HEADER, not
  target-side. engine_core.h declares memcpy FOUR incompatible ways across its DEFINE_ macros;
  two in one TU collide. NOT a safe cleanup — the in-tree note at ov_MAIN_012.c:14333 records
  that `extern memcpy` disables gcc's builtin and turns an inlined block-move into a CALL, so the
  declaration CHANGES CODEGEN. Probe one macro in one binary and byte-gate before any sweep.
- C (dedup_extend over the 129) stays blocked on B. Full context for both in the checkpoint.
2026-08-10 14:16:19 -06:00
Drew T 094bc4c2da chore(phase-30 S46-8/9): cascade findings + the family map + a corrected resume path 2026-08-10 13:04:23 -06:00
Drew T 4db662d1aa chore(phase-30 S46-7): record the 0/129 refutation — the ladder fixes drafts, the conflict is target-side 2026-08-10 11:05:23 -06:00