Commit Graph

1416 Commits

Author SHA1 Message Date
Drew T be2eaa1842 feat(phase-30 S38/S1c): re-sweep the matched-exemplar families after the type lift — 97 members banked
Families that returned 0/N before the 895-type lift now bank: 97 member-matches across 137 families
(1,138 failed; skipped 186 STRUCT-class by design, 106 unresolved-immediate, 6 not-stub).
R22 clean-fleet 140/140. Fleet 94.2 -> 94.3% instr / 88.9 -> 89.1% distinct / 96.29 -> 96.32% fn.

RESIDUE PRICED FROM THE SWEEP'S OWN .classified.txt PAYLOADS, not inferred: in the 400 most recent
failure records, 133 are genuine DIFF and the clear majority are `conflicting types for <sym>` —
the §103/§20 extern-conflict class, across ~12 overlays. That confirms S1b (wire reconcile_tu /
cast_call_sites into the --hseq path) is the correct next lever, and it is now justified by
measurement rather than by the plan's projection.

Method note worth keeping: those per-member diagnoses have been written on every sweep run for a
month and were never read — including by me, until after I had spent two probes and a manual
--stage-only round rediscovering one of them. Every remaining task now starts by reading the payload.
2026-08-04 19:04:56 -06:00
Drew T c57860db4e feat(phase-30 S38/S1a): lift 895 local types to engine_types.h — kills the type-scope sweep class
The free-sweep "wall" was a C parse error: a remapped member body names the EXEMPLAR's TU-local
types, which are undeclared in the sibling's TU, so gcc-2.7.2 parses the declarator as an expression
and dies before ever reaching codegen. extract_unit does carry typedefs, but only ones immediately
preceding the function in the preamble — types declared elsewhere in the exemplar's TU are missed.

Rather than patch the scanner per-family, remove the class: lift every liftable local type into the
shared header once. 895 types lifted, 6,196 local definitions stripped across 1,259 files.
R22 clean-fleet 140/140.

EXCLUDED s8/s16/s32/u8/u16/u32/f32/s64/u64/f64 — lift_types classified those common.h scalars as
liftable and lifting them would have been actively harmful. The tool's own visibility guard kept 8
local defs in src/ov_SC01_077/ov_SC01_077_o0.c, which does not include engine_types.h (stripping a
type out of a TU that cannot see the replacement DELETES it, and the link error that follows names
an unrelated data symbol).

Mechanism proven before scaling: lifting just 3 types took 0x801833f0's family from 0/6 to 6/6.
2026-08-04 18:46:30 -06:00
Drew T 97a6864677 docs(phase-30): adopt the Fable-5 frontier plan as T7 + persist the report
The Fable-5 agent's harness blocked it from writing to disk, so its full analysis existed ONLY in
the completion notification — one session away from being lost. Transcribed verbatim to
.run/fable_frontier/ANALYSIS.md and force-added (with its computed pools, pool_ovres.json), and
CURRENT_PHASE.md's new T7 points at it so future sessions know where the detail lives.

T7 supersedes T6's wave ordering on one number: across every sweep run this project has done,
blockers are ~24k PLUMBING vs 4,917 DIFF (5:1). Fixing plumbing moves work from the ~490 tok/ins
wave column to ~0, and S1 restores the propagation multiplier that makes every later wave ~3x
cheaper. DO S1 BEFORE ANY WAVE.

S1-S7 recorded with reachable-ins and tok/ins estimates. Provenance is explicit: the two headline
refutations were independently re-verified (23,211 classified files exist; 0x801833f0 went 0/6 ->
6/6 after the type lift, R22 140/140); the POOL NUMBERS are the agent's own computation and are
NOT re-verified — flagged in the file to verify before scaling a wave onto them (R14).

Standing pre-probe rule added: check h_norm identity across members BEFORE probing (an h_norm-
identical family returning 0% is a compile-error certainty), and read the classified files before
theorising about a sweep failure.
2026-08-04 18:40:14 -06:00
Drew T d053d71a27 docs(phase-30 S38): STRIKE my "x138 era is over" reading — the base rate is 5:1 PLUMBING, not codegen
A Fable5 frontier pass (read-only) refuted four S38 claims, each against data already in the repo:
 - "4 of the 8 big families collide by chance" -> all four classify PURE or IMM x138, and PURE means
   every differing word sits at a RELOC position, i.e. the OPPOSITE of chance collision. I printed
   diff_class in my own table and misread it. 0x80161418 has 552 already-matched siblings.
 - "0x80175820 / 0x80132018 are not templatable" -> IMM x137 (7,535 ins) and PURE x132 (6,072 ins).
 - "the free-sweep zeros are undiagnosed" -> both were PLUMBING, both diagnoses written by the sweep
   itself at probe time into .run/hseq_failed.*.classified.txt (23,211 such files exist).
 - "family_sweep hides the per-member error" -> false, struck.
THE BASE RATE settles it: across all sweep runs, blockers are ~24k PLUMBING vs 4,917 DIFF (5:1).

What survives: the open-member distribution really does skew small. What does not: the conclusion I
drew from it. Only the 2 GIANT walls survive scrutiny, and they are EXEMPLAR walls whose 138 members
each classify PURE — 50,094 ins riding on 2 cracks.

Newly visible and untargeted: 1,689 open-only h_norm clusters / 5,956 fns / 326,261 ins = 46% of all
open overlay instructions, at a 2.7x propagation multiplier; plus 250 fns / 12,981 ins byte-identical
to matched code (incl. the whale, open only in the 4 SC07s).

Ranked plan recorded: S1 (fix the 2 plumbing classes, re-sweep the 148 matched-exemplar families)
reaches 35-60k ins at ~10-25 tok/ins against a 490 t/ins wave baseline. S1-S4 move 80-115k ins to
~0 tokens and restore the propagation multiplier. DO S1 BEFORE ANY WAVE.

Standing pre-probe rule added: check h_norm identity across members first — if they are h_norm
identical, a 0% is a compile-error certainty, not evidence about codegen.
2026-08-04 18:36:51 -06:00
Drew T 91bb3ac76b feat(phase-30 S38): the free-sweep "wall" was a TYPE-SCOPE parse error — 0/6 becomes 6/6
family_sweep --hseq returned 0/6 on 0x801833f0 (328 ins, PURE, matched exemplar) and I recorded it
as evidence that h_seq families do not template. It was a C PARSE ERROR: the remapped member body
carries the EXEMPLAR's TU-local type names (PTag_801833F0 / Ft4_801833F0 / Drm_801833F0), which are
declared only in ov_SC02_028's TUs. Undeclared type -> gcc-2.7.2 parses the declarator as an
expression -> "parse error before `vtx'" two lines later. Never reached codegen.

Lifting the three types to src/shared/engine_types.h (lift_types --apply; each had ONE canonical
definition, no variants) turns the same sweep into 6/6 banked. R22 clean-fleet 140/140.

This is the §20 propagation cap resurfacing on the h_seq sweep path, where nobody had checked for it.

MY ERROR, RECORDED (R37/R14): I claimed in the S38 checkpoint and in commit commit:1410 that
"family_sweep reports banked/failed WITHOUT the per-member build error". That is FALSE. There are
23,211 .run/hseq_failed.*.classified.txt files on disk; the diagnosis for BOTH of today's zeros was
written by the sweep itself at probe time (0x80128c98's says "PLUMBING: conflicting types for
`cdFileLocTable'"). I asserted a tool limitation without checking for it, and then spent two probes
plus a manual --stage-only round rediscovering what was already in a file. Probe before costing.
2026-08-04 18:36:04 -06:00
Drew T 2483fc902a fix(tools): jr_isolate_all was SILENTLY DELETING asm-label-alias definitions during a repartition
ROOT CAUSE (byte-witnessed, P30 S38 — the fifth tool with this same blindness).
A function banked under the §37/§73 DEFINITION-SIDE ASM-LABEL ALIAS form is spelled with a private
C identifier and bound to its real symbol by a GNU asm label:

    void aF8018A860(s32, s16 *, u8 *, u8 *) __asm__("func_80183AF8");   <- decl, stays in preamble
    void aF8018A860(s32, s16 *, u8 *, u8 *) { ... }                     <- THIS emits func_80183AF8

overlay_src_split.addr_of() resolves `func_<hex>` arithmetically and everything else through `syms`.
`aF8018A860` matches NEITHER, so it returned None — and partition() keeps only items with a
resolved address, so the definition was dropped from EVERY region. The file was then rewritten
without it and nothing said so. One carve of ov_SC02_028 deleted the definitions emitting BOTH
func_80183AF8 and func_80184268; the overlay stopped linking with `undefined reference`, and six
wave-6 drafts were written off against that as a plumbing/compiler wall.

TWO FIXES:
 - CAUSE: overlay_src_split now builds an asm-label alias map from the source and resolves a
   definition through its EMITTED SYMBOL rather than its C name (verified: aF8018A860 -> 0x80183AF8,
   aF8018AFD0 -> 0x80184268 — exactly the two symbols the link was missing).
 - SILENCE: partition() and jr_isolate_all._partition() now REFUSE to rewrite a file when any
   construct's address does not resolve (R32), instead of discarding it. That guard alone would
   have surfaced this the first time it happened.

RESULT: 3 of the 6 alias-class wave-6 drafts bank immediately, for ZERO agent tokens —
func_801884D8 (137 ins) · func_80180B04 (251) · func_801380E0 (438). R22 clean-fleet 140/140.
The other 3 (the three LARGEST: 557/513/710 ins) have a second, size-correlated cause — open.

NOTE FOR THE FLYWHEEL: family_remap._alias_decl_for ALREADY handled this exact form, and its
docstring records the identical lesson ("that blindness was the WHOLE of the h_seq sweep's 137 'no
matched unit' skips. The tool, not the compiler (R35)"). The fix was never propagated. The alias
form needs ONE shared oracle, the way §134 comment-masking ended up on cdecl._mask — five tools
have now independently rediscovered it.
2026-08-04 18:30:01 -06:00
Drew T c21a310cce docs(phase-30 S38): measure the family frontier — the x138 era is over; the free-sweep lane is 0/0 UNDIAGNOSED
Answers "can we still derive an exemplar and free-crack hundreds?" with the distribution:
families YES, hundreds-per-crack NO. Only 8 families have 100+ open members — 2 permanent walls,
2 ledgered not-templatable, and 4 that are 14-25-ins functions whose h_seq skeleton collides by
CHANCE (0x80128c98 probed 0/138). The frontier is now 1,534 families at 2-4 members plus 3,807
singletons. A crack is worth 2-9 members, not 138 — wave 6's func_8017FEE0 (19 members, 4,485 ins)
was near the TOP of what remains. Throughput of cracks now beats leverage per crack, which argues
FOR the 64-target wave shape rather than against it.

The 147 matched-sibling families (66,971 ins) looked like free sweep fuel. Two probes returned 0
(0/138 small-skeleton, 0/6 on the top 328-ins PURE non-jr family). RECORDED AS A PENDING QUESTION,
NOT A WALL: the cause is undiagnosed, and this project has manufactured a false wall from exactly
this evidence before (P26's "families template ~0%" was overturned in P28 when the 0/8 turned out
to be a missing carve and the family then banked 102/115). family_sweep reports banked/failed
without the per-member build error, so DIFF and PLUMBING are indistinguishable at this level —
the same missing-payload gap as jtbl_family_bank's bare "gate-fail". One member through
harvest_verify with the error read settles ~26k instructions.
2026-08-04 18:20:12 -06:00
Drew T 8057709407 fix(.run/w6_pool.py): "attempted" must mean a wave that RAN, not a manifest that exists
Two fixes to the pool derivation:
 - the previously-attempted glob was `s*_wave.json`, which misses `w6_wave.json` — so wave 6's own
   failed targets would have been silently re-offered to wave 7;
 - but widening it to `*_wave.json` introduced the opposite defect: a STAGED manifest counted as
   attempted, so deriving a 16-target wave and then a 64-target wave made the second exclude the
   first's 16 best entries (pool 2,928 -> 2,913 -> 2,893 across three derivations, each poisoned by
   the last). Now a manifest counts only if its drafts directory exists: `<tag>_wave.json` ran iff
   `.run/<tag>/*/*.c` is non-empty. A manifest with no drafts is a PLAN, not a result.

Wave 7 staged in two sizes off one clean pool (2,913 fresh families / 432,020 open templ ins):
  .run/w7_wave.json    16 targets / 19,088 templ ins
  .run/w7_wave64.json  64 targets / 52,483 templ ins   <- the ~50k shape
NOTE the 50k now costs 64 targets, not 16: wave 6 harvested the head of the distribution (its top
single target was 15,152 ins), so the frontier is now a long tail of ~1,000-1,500-ins families.
2026-08-04 18:12:18 -06:00
Drew T bc04f65562 docs(phase-30 S38): checkpoint — wave 6 banked (+10,616 ins), the gate defect fixed, 9 drafts diagnosed
FLEET 96.29% fn / 94.2% instr / 88.9% distinct, R22 140/140 twice. Session banked 7 wave-6 heads
+ 25 propagated siblings = +10,616 instructions (12,368,236 -> 12,378,852; the digest delta matches
the hand-derivation exactly).

wave-metrics.md gains Findings 5 and 6:
 - RANK WAVES BY INSTRUCTIONS, NOT HEADS. Wave 6 banked ~45% more instructions than wave 5 while
   banking less than half as many heads, because a bigger head carries more instructions AND its
   family propagates at the same cost per sibling (func_8017FEE0: ONE 299-ins head -> 4,485 ins
   across 15 siblings, ~0 agent tokens). The metric to beat is POOL REALISATION (21%), not bank
   rate — and wave 6's bank rate is NOT comparable to waves 3-5 because the difficulty knob moved
   deliberately (median target 438 ins vs 143, mostly has_mid_jr).
 - A WAVE TALLY IS A COVERAGE CLAIM and needs its own assertion.

The 9 unbanked drafts are diagnosed and preserved, and 6 of them are ONE class worth cracking
first: `undefined reference` to a sibling that IS defined in the overlay but only via a
definition-side __asm__ alias (§37/§124) — the carve repartitions the object and separates the call
site from the alias definition. One fix frees 6 already-paid-for drafts and will recur in every
carve-heavy wave. The other two are genuine near-misses (close=47 REGALLOC-PERM, close=370).

Tooling committed for reuse: w6_pool.py (the pool derivation, now a script), w6_diag.py (runs the
REAL gate path — s36_capture.py splices without the carve and is wrong for jr targets),
w6_jtbl_prop.py (carve-path propagation with the per-family commit jtbl_family_bank requires).
2026-08-04 18:10:19 -06:00
Drew T 6b21af6a14 fix(tools): classify_fail truncated its diagnostic from the LEFT, severing the symbol name
These diagnostics are "<long path>:<position>: <message>", and the MESSAGE names the symbol —
which is the entire routing value of the PLUMBING/CC1-FAIL label. The old [:90] spent its budget
on the path and cut the payload mid-token, so a real wave-6 failure was labelled:

  PLUMBING: src/ov_SC03_001/..._jr_8017AE2C.c:(.text+0xc090): undefined reference to `func_801

with the symbol severed at four hex digits — unroutable. New _squeeze() keeps a short head (the
file is still identifiable) and the tail (the symbol), so the same line now ends
"undefined reference to `func_80143C74'".

Same family as the §58 red-herring guard directly below it and §136a: a label that cannot
distinguish its inputs carries no information, and one that drops the payload is worse than none.
2026-08-04 17:55:51 -06:00
Drew T 7247c68b60 feat(phase-30 S38): wave-6 propagation — func_8017EA84 x2 sibling slots
jtbl_family_bank (the §53 carve path; family_sweep --hseq refuses has_mid_jr
families by design). Each sibling individually byte-gated: carve -> extract ->
remap -> whole-binary build, kept iff byte-identical else reverted. Committed here
because jtbl_family_bank requires a clean tree between families (its per-sibling
revert restores from HEAD). R22 clean-fleet runs once over the whole batch.
2026-08-04 17:55:31 -06:00
Drew T 81c5cc559a feat(phase-30 S38): wave-6 propagation — func_80184C74 x5 sibling slots
jtbl_family_bank (the §53 carve path; family_sweep --hseq refuses has_mid_jr
families by design). Each sibling individually byte-gated: carve -> extract ->
remap -> whole-binary build, kept iff byte-identical else reverted. Committed here
because jtbl_family_bank requires a clean tree between families (its per-sibling
revert restores from HEAD). R22 clean-fleet runs once over the whole batch.
2026-08-04 17:54:54 -06:00
Drew T 8f3d8662b6 feat(phase-30 S38): wave-6 propagation — func_80183AE0 x6 sibling slots
jtbl_family_bank (the §53 carve path; family_sweep --hseq refuses has_mid_jr
families by design). Each sibling individually byte-gated: carve -> extract ->
remap -> whole-binary build, kept iff byte-identical else reverted. Committed here
because jtbl_family_bank requires a clean tree between families (its per-sibling
revert restores from HEAD). R22 clean-fleet runs once over the whole batch.
2026-08-04 17:53:33 -06:00
Drew T c44b980fe4 feat(phase-30 S38): wave-6 propagation — func_80181CE4 x6 sibling slots
jtbl_family_bank (the §53 carve path; family_sweep --hseq refuses has_mid_jr
families by design). Each sibling individually byte-gated: carve -> extract ->
remap -> whole-binary build, kept iff byte-identical else reverted. Committed here
because jtbl_family_bank requires a clean tree between families (its per-sibling
revert restores from HEAD). R22 clean-fleet runs once over the whole batch.
2026-08-04 17:52:14 -06:00
Drew T 65f0184f7d chore: regenerate docs/family-hseq.md after the wave-6 banks
Derived digest; committed so the next family map regen has a clean base.
2026-08-04 17:50:35 -06:00
Drew T ba87a9b256 feat(phase-30 S38): wave-6 propagation family 1 — func_8017FEE0 x15 siblings
jtbl_family_bank (the §53 carve path — family_sweep --hseq correctly REFUSED these as has_mid_jr
families, warning that a 0% from the non-carve path would be a TOOL artifact, not a wall).
func_8017FEE0 (299 ins, cross-address family of 19 open siblings): 15 BANKED, 4 gate-fail.
Each sibling individually byte-gated by jtbl_family_bank (carve -> extract -> remap -> build, keep
iff byte-identical else revert). R22 clean-fleet runs once over the whole propagation batch; this
commit exists because jtbl_family_bank REQUIRES a clean tree between families (its per-sibling
revert restores from HEAD, so an uncommitted prior family would be destroyed).
2026-08-04 17:50:05 -06:00
Drew T e977205bb8 docs(cookbook): §139 — a gate that greps for verdicts must assert 1:1 accounting
The wave-6 gate printed BANKED 5 / FAILED 1 over SIXTEEN drafts and nothing said so. Captured with
the three corollaries that outlive the bug (R30 — written in the session that produced them):
 (a) the byte-gate is a perfect CORRECTNESS oracle and a NULL COVERAGE oracle (R34 again), so every
     wave-level tally is a coverage claim and needs its own assertion;
 (b) a pipeline's exit status is the LAST command's — "family_sweep ... | tail" hid a non-zero exit
     in this same session; use pipefail/PIPESTATUS or the tail IS the error handler;
 (c) a reverted CONFIG needs a re-extract before the next measurement means anything (the Phase-20
     R22 corollary; skipping it made three genuinely-banked functions read as failures).
Plus the inverse-lookup trap: a just-banked head LEAVES its family's members list and becomes
exemplar.kind='matched', so a member-list lookup reports "no family" for exactly the heads you just
banked. Distinct from §138 rule 4, which governs target SELECTION.

Index regenerated: 393 sections, 3 new symptom keys.
2026-08-04 17:50:05 -06:00
Drew T 73321fe2c2 fix(phase-30 S38): the gate was booking CRASHES as silence — 10 of wave 6's 16 drafts vanished
THE DEFECT CHAIN (byte-witnessed, both ends fixed):
1. harvest_verify._reload_corpus re-applied the `--src` filter AFTER a jtbl carve. Following a
   carved stub to its NEW TU is that function's entire documented purpose, and it was deleting the
   very stub it had just followed. Then:
     _stubs loses fn -> render() raises KeyError -> UNCAUGHT -> _jtbl_restore(snap) never runs
     -> the carve is STRANDED in config/ + src/ -> every LATER group in the same gate run then
     built against a tree the earlier crashes had mutated.
   line 136 already calls --src "an optional filter, not a location oracle"; this was the one place
   treating it as one. Fix: the filter never drops a draft under verification, wherever it now
   lives, + an R32 loud report if a working stub vanishes across a reload (which also repairs
   _touched/baseline — a carved fn missing from _stubs left its new TU unbaselined, so the revert
   path could not have restored it either).
2. .run/s6f_gate.py never checked the child's returncode — it grepped stdout for VERIFIED:/FAILED:
   and booked "neither" as NOTHING, printing a clean-looking tally over 10 missing verdicts. This
   is the §136a defect I logged against my own capture tool last session, in the gate itself.
   Fix: 1:1 accounting assertion (banked+failed+no-verdict == drafts), the child's rc + output tail
   on anything unaccounted, and exit 1 — a crashed child may have stranded a carve, so it must
   never look like success.

PROOF THE FIX IS NOT COSMETIC: func_8017EA84 (579 ins) now carves and banks BYTE-IDENTICAL. The old
tool reported it as nothing at all.

BANKED 7 (R22 clean-fleet 140/140 from `make clean` + extract-all + check-all):
  func_8017EA84 ov_SC02_000 (579) · func_8017FEE0 ov_SC02_026 (299) · func_80181CE4 ov_SC03_111 (491)
  func_80183AE0 ov_SC03_112 (240) · func_80184C74 ov_SC06_018 (288) · func_80180F98 ov_SC03_097 (263)
  func_801841C8 ov_SC02_035 (44)

MY OWN ERROR, RECORDED (R37/R14): after reverting the stranded carves I re-extracted ONE overlay,
not all 16 — the Phase-20 R22 corollary (a reverted CONFIG needs a `make extract`, not just a
revert) which I know and skipped. Run 2 therefore read WORSE than run 1: three genuinely-banked
functions failed against stale asm. Re-extracting the 16 touched binaries produced the honest run.
A gate result measured against stale asm is not a measurement (R35).

.run/w6_diag.py: run the REAL gate path for one (ov,fn) with the child's full output. s36_capture.py
splices without the carve, which is the wrong path for a table-bearing fn (§61b: the carve must
follow the splice) and produces a failure that is an artifact of the diagnosis.
2026-08-04 17:41:43 -06:00
Drew T fd1bdd4b2f chore(phase-30 S38): preserve wave-6 drafts before gating (5.2M agent tokens)
16 drafts, 14 claiming MATCH. .run/ is gitignored, so these are force-added: the wave-5 restart
proved the Workflow resumeFromRunId cache is SAME-SESSION-ONLY, and a draft that has to be re-earned
costs ~300k tokens. Gate follows; the byte-gate is the sole arbiter (G3/P9) and these are claims.
2026-08-04 17:24:04 -06:00
Drew T e5380ff6fb fix(tools): family_hseq's stdout claimed "fleet" for an OVERLAYS-ONLY number
load() globs .run/sig.ov_*.jsonl, so main and the resident are absent from every denominator —
the numbers run ~0.3-1.0pp above the authoritative `make report` fleet (measured today: 96.6/94.6/
89.7 vs the digest's 96.28/94.1/88.7). docs/family-hseq.md has always carried the "(overlays)"
qualifier; the stdout print did not.

That asymmetry matters because stdout is the channel a session actually reads and transcribes into
a checkpoint — a right number under a wrong label is how a wrong number propagates (R35: the
measurement was fine, the instrument's LABEL was the defect; R14: a checkpoint that disagrees with
the digest must lose, and it can only lose if the disagreement is visible).

Print-only; the metric itself is unchanged and correct for its scope.
2026-08-04 16:14:13 -06:00
Drew T 139e21118b docs(phase-30 S38): wave 6 launched — pool derivation is a script now, + 2 derive-don't-assert fixes
- .run/w6_pool.py: THE pool derivation, finally a script instead of inline python (R33).
  Ranks by OPEN templatable weight (corpus.stubs over the family map's member list, §138 rule 4 —
  never off the map's `exemplar` field), carries the walls/ledgered-residual exclusion set, drops
  any family whose address was attempted-and-still-open in a prior wave (83 addrs), and enforces
  one target per (overlay, TU) so a wave cannot manufacture its own §138-rule-2 type-tag conflict.
  Pool: 2,928 fresh families / 476,611 open templatable ins.
- wave 6 = 16 targets / 50,596 open templatable ins (3x wave 5), large-function heavy
  (median ~270 ins, max 947); prompt carries the S37/W6 block (stage the big ones; cross-address
  families need STEP 0 because searching by address cannot find their twin; the PAIR rule).
- TWO R37 FIXES TO THE MANIFEST ITSELF, both "asserted, never derived":
  * `seed` was an arbitrary i%2 alternation carried over from the previous wave's shape — it
    controls whether the prompt claims a cached Ghidra seed EXISTS. Now derived from
    .run/ghidra_c/ on disk: 9 of 16, not 8 by alternation.
  * `model` routed by MEASURED band, not the stale §136i ladder: Sonnet is measured 81-100%
    first-pass over 125-793 ins, so func_8017C974 (947) is outside it and goes to Opus directly.
- CURRENT_PHASE.md: in-flight checkpoint (the wave-5 restart lost 2.7M tokens of ungated drafts;
  this block says force-add the drafts and resume by GATING, never by re-running).
2026-08-04 16:13:14 -06:00
Drew T bd097a9010 docs(phase-30): checkpoint — name the code commit correctly + add a staleness self-check 2026-08-04 13:47:42 -06:00
Drew T b42b1885ae docs(phase-30): SESSION-33..37 checkpoint — wave 5 banked, nothing owed; wave-metrics findings reordered 2026-08-04 13:43:53 -06:00
Drew T af16c38a62 feat(phase-30 S37): wave 5 banks 16/16 with ZERO reconcile + 26 members; wave metrics logged
Fleet 96.27 -> 96.28% fn-count / 94.1% instr / 88.6 -> 88.7% distinct (77,765
uniq). R22 clean-fleet: 140 passed, 0 failed of 140. dedup 1910/0.

16 targets / 16,884 templatable ins. 19 agents, 2.71M tokens, 82 min wall.
The gate banked 16/16 — the FIRST perfect gate of the session, and the first
needing NO reconcile at all. Sweep: +26 members / 3 failed across 17 overlays.

NEW: docs/wave-metrics.md — the wave-by-wave performance log, with the derivation
commands so future rows are COMPUTED, not hand-transcribed (R33). Four findings,
each recorded with its caveat rather than as a bare number:

 1. THE PROMPT IS THE LEVER, AND THE AGENTS WRITE IT. Bank rate 76 -> 77 -> 100
    -> 100 -> 100% with models and gate held constant. The jump was STEP 0 (a
    magic-literal grep of src/, ahead of engine_core.h) — which came from a
    wave-2 agent's index_gap report. Caveat recorded: waves 3-5 targets also
    trended easier, so the mechanism is the durable claim, not the exact %.
 2. pipeline() vs batched parallel(): 136 min/14 targets -> 82 min/16 targets,
    parallelism 2.5x -> 3.8x. The two-batch design was a hard barrier with 37-50
    min dead gaps; the harness already caps at 16 so it bought nothing. Floor
    recorded honestly: the slowest agent is still ~50 min of real match_one
    iteration, so the lever there is target SELECTION, not concurrency.
 3. ECONOMICS: ~170-300k tokens per banked head in the stable regime — but a head
    is not the unit of value. Head + propagated members is, and sweep yield is
    BIMODAL not average (21/21 vs 18/165), because it is a property of the FAMILY.
    Averaging those two predicts nothing.
 4. A perfect gate is a signal the prompt rules landed. Waves 1-4 each needed 1-2
    post-gate reconciles; wave 5 needed zero. The reconcile lane is the fallback,
    not the plan. Lifetime 21/22.
2026-08-04 13:42:58 -06:00
Drew T 3f51101ca9 docs(phase-30): SESSION-33..37 checkpoint — PAUSED; 16 ungated wave-5 drafts preserved in git
Paused at Drew's request for a Windows restart. Nothing running, tree lock free,
tree clean (R23 db churn aside). R22 run 19x this session, 140/140 every time.

THE ONE THING OWED: `.run/s37/*/func_*.c` — 16 wave-5 drafts, all claiming MATCH,
NONE gated. Force-added to git (.run/ is gitignored) because they cost ~2.7M
agent tokens and Workflow's resumeFromRunId cache is SAME-SESSION-ONLY, so it
does not survive the restart. Resume by GATING them, not by re-running the wave.
Also preserved: the wave scripts (.run/s36w.js, .run/s37w.js), manifests, the
hardened gate driver, and the four capture drivers.

MEASURED THIS SESSION (both answer questions Drew asked):
- The wave PROMPT is the lever. Bank rate 76% -> 77% -> 100% -> 100% on the same
  models and the same gate, prompt the only variable. The jump was STEP 0 (a
  magic-literal grep of src/, ahead of engine_core.h) — and that step came from a
  wave-2 agent's index_gap report, i.e. the agents write the next prompt.
- The pipeline() fix, before/after: wave 4 parallel() 14 targets / 136 min /
  2.5x parallelism; wave 5 pipeline() 16 targets / 82 min / 3.8x. 40% faster on
  14% more targets. The two-batch design was a hard barrier with 46-min dead gaps
  at each boundary; the harness already caps at 16 so the batching bought nothing.

Housekeeping: removed 3 stray cc1 intermediates (t.i, t.i.greg, t.s) that an
agent left at the repo ROOT — scratch belongs under .run/ (R12), same class as
the gccdump.lreg noted at the Phase-24 close.
2026-08-04 13:29:51 -06:00
Drew T 9064840757 feat(phase-30 S36): wave 4 banks 14/14 + 26 members — step 0 is now the agents' default move
Fleet: R22 clean-fleet 140 passed, 0 failed of 140. dedup 1910/0.

14 targets / 16,844 templatable ins. 17 agents, 3.0M tokens. Claimed 14/14; the
whole-binary gate banked 13, the 14th on reconcile. Sweep: +26 members / 0 failed
across 18 overlays. Reconcile lane 21/22 lifetime.

STEP 0 HAS BECOME THE AGENTS' DEFAULT MOVE. Nearly every wave-4 verdict cites the
cross-overlay magic-literal grep BY NAME, several reporting `index_gap: none`
because it resolved the target in one pass with no cookbook derivation needed:
 - func_8018BED0: grep 0xE100000A -> func_80188C04 (ov_SC03_089), verbatim, MATCH first try
 - func_8018BAB4: grep D_800A6610/D_800B9A02 -> func_801887E8, verbatim + callee swap
 - func_8017ED54: grep named all 5 family members -> reused func_8017D9F0's body, 14 data remaps
 - func_8017C290: grep found byte-identical twins ALREADY banked in two other overlays
Bank rate by wave, same models + same gate, prompt the only variable:
  76% -> 77% -> 100% -> 100%.

THE ONE FAILURE IS THE §138 RECONCILE-DIRECTION RULE, in its purest form:
`redefinition of struct B16_8018A758` — the agent copied its sibling's struct tag
verbatim, and that sibling had banked into the SAME TU earlier in THIS wave. Decl
ABOVE the splice => DELETE the duplicate (do not rename it). Worth noting the
mechanism: a wave can create its own reconcile work when two targets share a TU.

func_8018A808's own family swept 0/14 — its members are the per-location kind
that do not template (the settled h_seq ceiling), not a plumbing failure.
2026-08-04 12:05:32 -06:00
Drew T cbf0bce26c feat(phase-30 S35): wave 3 banks 13/13 — the flywheel paid off one wave later
Fleet 96.24 -> 96.25% fn-count / 94.0% instr / 88.4 -> 88.5% distinct.
R22 clean-fleet: 140 passed, 0 failed of 140. dedup 1910/0.

13 targets / 17,644 templatable ins. 14 agents, 2.7M tokens. Claimed 13/13;
the whole-binary gate banked 12, the 13th on reconcile (another §37/§124
SELF-axis alias — the TU declares `(void)`, the def takes an s32). Reconcile
lane 20/21 lifetime. Sweep: +21 members / 0 failed across 16 overlays.

THE FLYWHEEL, MEASURED ACROSS THREE WAVES (same models, same gate):
  wave 1  baseline prompt              15/17 claimed -> 13 banked (76%)
  wave 2  + the S33 rules              11/13         -> 10        (77%)
  wave 3  + S34 magic-grep as STEP 0   13/13         -> 13       (100%)
Multiple wave-3 agents report the cross-overlay magic-literal grep landing the
answer on the FIRST search. One found a banked twin whose own header comment
already documented it as byte-identical to the new target, so the body
transferred verbatim with only file-local type suffixes renamed. That is the
wave-2 discovery paying off one wave later (R16).

Sweep quality also differed for a reason worth keeping: 21/21 here vs 18/165 in
wave 2. Wave 2's two big families are the per-location kind I then probed and
ruled out (BUILD OK + byte diff = genuine per-member codegen, not plumbing);
wave 3's are genuinely templatable. The sweep rate is a property of the FAMILY,
not of the wave.

TOOLING: an agent left 8 scratch files (test_licm*.c) in the drafts dir and the
gate driver died on `int('full', 16)`, taking the whole gate with it. Hardened to
treat a non-conforming filename as a NAMED, COUNTED skip rather than a crash
(R32) — a drafts dir is agent-writable by design, so it must not be trusted to
contain only deliverables.
2026-08-04 09:42:58 -06:00
Drew T 6b30335eb7 docs(phase-30): SESSION-33/34/35 checkpoint — fresh-session safe; 5 distilled rules, the h_seq ceiling re-confirmed by probe 2026-08-04 07:16:55 -06:00
Drew T 7a4abddbfa feat(phase-30 S34): wave 2 — 10 heads + 18 members; the search order had a cross-overlay hole
Fleet 96.24% fn-count / 93.9 -> 94.0% instr / 88.4% distinct. R22 clean-fleet:
140 passed, 0 failed of 140. dedup 1910/0.

WAVE 2: 13 targets / 37,943 templatable ins. 19 agents, 4.5M tokens. Claimed 11
MATCH; the whole-binary gate banked 9, +1 on reconcile (func_8017E5D0 via the
§37/§124 DEFINITION-side alias — the TU declares it `(void)`, the byte-true def
takes a pointer). Reconcile lane now 19/20 lifetime. 18 members swept.

THE FINDING (an agent caught a hole in our own procedure). §136c's search order
— engine_core.h near-twin -> same-TU banked sibling -> the .s — is entirely
SAME-TU or SHARED-HEADER scoped, so no step can reach a banked twin in a
DIFFERENT overlay's TU. But the large template classes live cross-overlay by
construction. func_80188C04 (328 ins) turned out byte-identical to an
already-banked func_801833F0 in ov_SC02_028, and ONE command found it:
`grep -rn "E100000A" src/` — a magic word lifted from the target .s. The body was
then reused verbatim, only file-local suffixes renamed. Promoted to STEP 0 of
§136c, ahead of engine_core.h.

That compounds with the manifest finding this session: the family map's
`exemplar` is an IN-FAMILY pointer, so a family whose twin is banked elsewhere
looks un-cracked — and the pointer can itself name an ALREADY-BANKED instance,
hiding the family from any ranking built on it. Derive open sites from
corpus.stubs over the member list instead. Measured on this wave: ranking off the
map's exemplar gave 16,696 templatable ins; deriving from corpus.stubs gave
41,023, including a 55-ins family open in 138 overlays and a 46-ins one in 133.

HONEST ON THE SWEEP: those two big families templated 18/165. That is the known
h_seq refusal ceiling, not a new wall. One agent reported "all 10 members
distance 0" — that is NORMALIZED distance, not h_exact, which is why
dedup_propagate correctly answered reach<2. Do not read a normalized-distance
claim as an h_exact guarantee.

LEDGERED (real residual, not paperwork): func_8017F7B4 — needed its sibling's
type names AND a data asm-label alias for a u8-shaped symbol, and still refuses.
Plus func_8017C294 (DIFF close=12: 4 register/schedule permutations + a frame
where I can get the 0x138 size OR pEnd's slot at 0x108, not both) and
func_801898E4.
2026-08-04 07:14:28 -06:00
Drew T 138e21c7d4 feat(phase-30 S33e): both gate-refused drafts reconciled — the lane is 18/18 lifetime
Fleet 96.23 -> 96.24% fn-count / 93.9% instr / 88.3 -> 88.4% distinct.
R22 clean-fleet: 140 passed, 0 failed of 140. dedup 1910/0.

func_8017D318 (184 ins) + func_80181EE0 (198 ins) both banked, + 6 members swept
(6 per-overlay variants failed — ledger material, not a lever).

THE RECONCILE DIRECTION DEPENDS ON WHERE THE TU'S DECL IS, and picking wrong
CREATES the next error (-> cookbook §138):
 - decl ABOVE the splice point  -> DELETE the draft's duplicate (§100).
   func_8017D318: the TU defines MATRIX_/SVECTOR_8017C290, D_801EA8C0 AND a
   `struct PW8017C290` tag above it; I missed the tag on the first pass, so it
   took two rounds.
 - decl BELOW the splice point  -> KEEP a decl in the TU's EXACT shape and cast
   at the use (§17a-1 D2). func_80181EE0: I removed its decl assuming the TU
   provided one; the TU's `extern int func_80143C74(short *, int);` is at L5082,
   ~180 lines BELOW the splice at 4901, so the identifier went undeclared.
Grep the TU for the symbol and compare line numbers with the stub line first.

MY OWN §136a VIOLATION, recorded: the blocker-capture filtered the build log for
`error|conflicting|undefined reference` and reported "NO COMPILE ERROR" on a
build that was failing with `redefinition of struct PW8017C290` and
`'func_80143C74' undeclared` — neither phrase matched. A narrow keyword filter is
exactly how a real error goes unseen, which is the thing §136a exists to say.
Widened to keep any line naming a source position.
2026-08-04 03:34:51 -06:00
Drew T 0bdc7f44a0 feat(phase-30 S33d): Sonnet wave — 13 heads + 65 members banked (78 instances)
Fleet 96.21 -> 96.23% fn-count / 93.8 -> 93.9% instr / 88.0 -> 88.3% distinct
(+73 unique fns). R22 clean-fleet: 140 passed, 0 failed of 140. dedup 1910/0.

THE WAVE. Re-ran S10's 17 unbanked targets (26,227 templatable ins) at LOW
concurrency in two batches of ~9 — S10's finding was that 14 of 30 agents were
SERVER-throttled, i.e. the limiter is capacity, not capability. Targets
re-derived against corpus.stubs first (R35): all 17 still live, paths verified.
25 agents, 6.87M tokens, ~2.8h. Claimed 15 MATCH; the whole-binary gate — the
sole arbiter (G3/P9) — banked 13, then family_sweep propagated 65 members across
38 overlays.

HEADLINE: func_8017D174 (793 ins) — the largest single crack of this phase. Its
agent closed two compiler-internal residuals jointly: a §137 allocno-priority tie
between &g.sz0/&g.sz1 (R=7, L=607 vs 606 -> 230/231) that spilled the wrong one
and cost a load-delay nop in BOTH switch arms, and a sched2 rotation in the
outer-loop head block that survived 470+ statement orderings. Fix was four
zero-byte asms: two `"=r"/"0"` re-ties splitting wz's live range, plus two
volatile sliders placed in a DIFFERENT basic block so they lift the live-length
count without perturbing the head schedule.

THE 4 NON-BANKS SPLIT CLEANLY (§136b — none is a wall on one attempt):
 - func_8017E2EC (close=20) and func_80186E24 (close=187): honest DIFF verdicts,
   real codegen residuals, ledger material.
 - func_8017D318 and func_80181EE0: claimed MATCH, gate refused -> the known
   match_one->gate gap, which is DECLARATION plumbing (agents cannot run the
   gate, so a TU-level conflict is invisible to them). Routed to the reconcile
   lane, not retired.

AGENT-REPORTED INDEX GAPS worth acting on (the flywheel closing on itself):
 - no symptom key for "schedule rotation at a loop-head block that NO statement
   permutation reaches" — the index's nearest line points at §76 regalloc, and
   the decisive doc was gcc-2.7.2-map/sched.md, which no scheduling symptom
   cross-references.
 - §137 is written as a two-compile arithmetic on ONE contender pair; the real
   fix here was an N-zero-byte-insn budget that ties only for N in {1,3,4} and
   splits the WRONG way for N=2, so a naive "add one slider, add another" walk
   silently regresses.
 - no key for "gcc hoists a loop-invariant SYMBOL_REF base out of a loop the
   target keeps in the `sym(reg)` macro form" (~105 of func_80186E24's 187).
2026-08-04 03:27:54 -06:00
Drew T b497ee1649 feat(phase-30 S33c): PROPAGATE head COMPLETE — func_801466F0 x137 took three fixes + a type-lift
Fleet 96.17 -> 96.21% fn-count / 93.8% instr / 88.0% distinct; dedup 1909 -> 1910
groups, 0 failed, C1 241216/241216. R22 clean-fleet: 140 passed, 0 failed of 140.

The head is now 5/5 classes, 18,545 templatable ins, all banked this session from
a standing start of 0.

func_801466F0 had sat since S6b behind THREE separate blockers, each of which
looked sufficient on its own to explain the failure:
 1. Its definition is under a §37/§73 ASM-LABEL ALIAS (`aF801466F0` in C, bound to
    the real symbol by `__asm__`), and dedup_propagate.find_site anchored its head
    regex on the literal `func_<ADDR>` — structurally blind to the form, returning
    None, which every caller reads as "not matched". Now reuses
    family_remap._alias_decl_for rather than growing a second matcher (R33).
 2. That matcher was itself blind to the WRAPPED (multi-line) declaration — the
    §134 shape, third tool. Fixed by matching over the joined text and mapping the
    offset back to the decl's FIRST line (extract_unit carries from there).
    Regression control: the single-line form still resolves. Fleet census after:
    2,768 of 2,768 alias sites resolve, 0 missed.
 3. Its record type was a draft-local typedef, so the body failed
    compiles_standalone. Lifted Rec801466F0 to src/shared/engine_types.h INSIDE
    the include guard (the SESSION-19 double-include note) and switched both the
    macro and the exemplar to it — byte-neutral, gate-proven.

Probed on ONE member before the fleet run: byte-identical 9052dc0e first try.

MEASURED, NOT INHERITED (R37): the S6b note frames the alias-regex gap as a CLASS
of missed work. It is ONE function — 91 distinct alias decls fleet-wide, the
per-line matcher resolved 90. Recording it so a future session does not scope a
phase against a class that does not exist.

cookbook §138 extended with the alias-form tool boundary and the three-blocker
story; index regenerated.
2026-08-04 00:44:33 -06:00
Drew T 4f6b0e8de1 feat(phase-30 S33b): PROPAGATE head 82% banked — 15,257 of 18,545 ins, four levers
Fleet 96.10 -> 96.17% fn-count / 93.7 -> 93.8% instr / 88.0% distinct.
dedup 1908 -> 1909 groups, 0 failed, C1 241078/241078.
R22 clean-fleet: 140 passed, 0 failed of 140.

  func_80147364  4,110  x137  definition-side asm-label alias
  func_8016BA68  3,886  x134  dedup_extend + the MIRROR decl relax
  func_8012F274  3,973  x136  hand-authored macro, source overlay excluded
  func_8012A598  3,288  x138  cdecl._mask backscan fix + shared-type switch
  func_801466F0  3,288  OPEN  the wrapped-alias regex — measured as ONE function

THREE DISTINCT CARRY VARIANTS were hiding in one "CARRY-FIXABLE" bucket, and
only one is a tool bug (-> cookbook §138):
  - a MULTI-LINE comment halts the preamble backscan -> fix the tool (cdecl._mask)
  - a draft-local `struct Tag {…}` -> switch the exemplar to the SHARED type
  - a file-scope `static inline` helper -> hand-author, EXCLUDE the source overlay
The third is the sneakiest: gcc-2.7.2 accepts implicit function declarations, so
the extracted body PASSED compiles_standalone with the helper undeclared and the
miss surfaced only as a whole-binary byte DIFF 137 gates later. Instantiating
that macro in the SOURCE overlay is a duplicate definition (its file-scope helper
is still there), so the shape is `--source-overlay X --binaries <all-but-X>`;
`--binaries` alone removes the source from the scan pool and errors.

TOOL BOUNDARY: once a group's members are DEFINE_func_*() sites, dedup_propagate
cannot extend it (find_site never returns a `def`). dedup_extend is the tool for
an already-macro-ized group — and `dedup_extend --check-only` across ordinary
overlays is a cheap fleet-wide wiring census (measured: exactly 1 group per
overlay, so no hidden backlog).

MEASURED, NOT INHERITED (R37): the S6b note frames _alias_decl_for's single-line
regex as a CLASS of missed work. It is not — 91 asm-label alias decls exist
fleet-wide, the regex matches 90, and the single miss is func_801466F0. Worth
3,288 ins, but a one-function fix. Correcting the expectation so a future session
does not scope against it.
2026-08-04 00:30:56 -06:00
Drew T 356373efab fix(phase-30 S33b): the PAIR rule — my 42-decl relax did NOT unblock the lane; the mirror form did
HONEST CORRECTION to commit:1382. That commit's message implies the 42 `(void)`
relaxes unblocked the PROPAGATE remainder. They did NOT: the re-run banked 0/1
in all 134 overlays with the same error, because DEFINE_func_8016BA68 declares
func_80146C3C `(u8*)` — the MIRROR of the EXTEND-lane pair — and my relax only
touched the `(void)` direction.

Root cause is the R37 shape a third time: I bucketed by SYMBOL and stopped. The
lever is set by the (macro-shape, TU-shape) PAIR, and the same symbol conflicts
in BOTH directions across this fleet. One awk over the macro I was ACTUALLY
fixing — which I ran for the EXTEND macros and not for this one — shows the pair
before a 134-build run. §138 amended with the PAIR rule; correction logged in
CURRENT_PHASE.md rather than rewritten out of history.

The 42-decl relax still stands: byte-neutral, R22 140/140, removes a real
conflict class. It just did not do what I predicted.

THIS commit relaxes the 2 remaining `(u8*)` decls (uses are cast; `()` is
compatible with the (void)/()/(u8*) forms the fleet carries and no decl of this
symbol has a default-promotion param). R22 clean-fleet: 140 passed, 0 failed.

ALSO: tools/overlay_src_split.py `_split_macro_body` — the §134 sweep's one real
target, fixed. It carried the identical single-line-only comment test, and it
decides where a macro body's file-scope externs END, so a multi-line comment
truncated the extern set. SIZED FIRST: 38 live lines in engine_core.h macro
bodies hit it today. Now decides on cdecl._mask (one oracle, R33) with the
length-preservation invariant asserted (R32). Proven both directions by a
control: pre-fix it stopped at `/* multi` carrying 1 of 2 externs and treated the
comment as the definition head; post-fix both externs carry and the def head is
correct. Not in the gate path (only o0_subsplit + jr_isolate_all import it).
2026-08-04 00:16:23 -06:00
Drew T 7a6a09379f fix(phase-30 S33b): relax all 42 func_80146C3C decls — the PROPAGATE remainder is the SAME symbol
Diagnosed the 11,147-ins PROPAGATE remainder with one probe, in §138's order:
1. ONE COMMAND, NO BUILD: the originals of BOTH 0x8016BA68 and 0x8012F274 are
   sha1-identical across ov_SC07_006 / ov_SC06_025 / ov_SC01_000 / ov_SC01_077 /
   ov_SC03_001 -> the registry is sound; the cause is TU context.
2. ONE BUILD in an excluded overlay named it: `conflicting types for
   func_80146C3C` — the SAME symbol as the EXTEND lane, same (void)-vs-(u8*)
   shape, same one-token lever. The 137 [exclude] lines were one declaration.

Relaxed the remaining 42 `extern void func_80146C3C(void);` in engine_core.h to
`()`. Measured safe BEFORE editing (§138): every fleet decl of the symbol is
`(void)/()/(u8*)/(u8 *a0)` — no default-promotion param anywhere, so gcc-2.7.2's
`()` rule cannot bite — and every use in the header is a no-arg call or already
cast, so it is codegen-neutral. R22 clean-fleet: 140 passed, 0 failed of 140.

TOOL BOUNDARY worth recording: `dedup_propagate` CANNOT finish this one. The 4
SC07 members are now `macro` sites, so `find_site` never returns a `def` and the
auto-source scan errors with "no source overlay has it matched". Extending an
already-macro-ized group is `dedup_extend`'s job. Probe: exactly 1 extendable
group per ordinary overlay — so the fleet has no hidden wiring backlog beyond
this function (a useful negative, R32-shaped).

Also logged: the §134 scanner sweep is sized and has ONE real target —
tools/overlay_src_split.py:345 (_split_macro_body) carries the identical
single-line-only comment test, and it decides where a macro body's file-scope
externs END, so a multi-line comment there silently truncates the extern set.
The other scanners in that file track block-comment state; split_src_region.py
and family_remap.py already handle the multi-line form.
2026-08-04 00:11:42 -06:00
Drew T 3daa647bb3 docs(phase-30 S11): cookbook §138 + SESSION-33 checkpoint
§138 — "the propagation lanes: a gate refusal is a DECLARATION, and which lever
you owe depends on blast radius". The durable content of this session:
- the 4-lever triage table ranked by blast radius, and the rule to grep the
  fleet's decl shapes BEFORE relaxing to `()` (illegal only against a
  default-promotion param — 4,020 decls measured, 8 of 36 banked for one token)
- `volatile` in the host TU is a SCHEDULING BARRIER that masquerades as a codegen
  wall; the tell is a positional shift with a `nop` at a delay slot, and the
  h_exact contract is confirmed/refuted in ONE command with no build
- the DEFINITION-side asm-label alias as the only zero-radius escape when the
  fleet canon disagrees on a promoting param (1,725 in-tree precedents)
- rank a lane by measured concentration, not class count (5 of 45 classes carried
  89%), and `--recover` is not a retry (16/16 on drafts, 4/138 on a propagation)
- §134 multi-line blindness recurring in a second tool; decide on `cdecl._mask`
- the waiter rule CORRECTED: `pgrep -x make` is wrong for a campaign of
  sequential makes, `pgrep -f` self-matches, `nohup … &` signals the wrapper

Checkpoint refreshed and placed below the task checklist (fresh-session safe):
fleet 96.10 / 93.7 / 88.0, dedup 1908/0, R22 140/140 four times this session,
nothing running, lock free. Three named next items, none yet diagnosed against a
build — the PROPAGATE head remainder (11,147 ins), the 41-class tail (2,316),
and EXTEND's last 5 (the whale needs the §38 -O0 route; dedup_extend should
refuse-and-name that class per R32).
2026-08-03 23:55:53 -06:00
Drew T 62042f65ca fix(phase-30 S11): multi-line-comment blindness in dedup_propagate; func_8012A598 x138
Fleet 96.06 -> 96.10% fn-count / 93.7% instr / 88.0% distinct; dedup 1907 -> 1908
groups, 0 failed, C1 240807/240807. R22 clean-fleet: 140 passed, 0 failed of 140.

func_8012A598 (3,288 templatable ins) was being written off as CARRY-FIXABLE.
It took TWO fixes; either alone leaves it skipped.

1. TOOL (R33) — find_site's preamble backscan. The SESSION-18 fix handled blank,
   `//`, and SINGLE-LINE `/* … */` lines, but a MULTI-LINE block comment still
   halted the walk: its middle lines start with `*` and its last line ends `*/`
   without starting `/*`. So the three externs above the body were dropped and
   the body then failed compiles_standalone on now-undeclared data. This is the
   §134 multi-line-blindness class — S6b fixed the identical shape three times in
   family_remap (D1/D2/D5) and this copy was never reached.

   Fixed by deciding skippability on `cdecl._mask` — the project's ONE masking
   oracle — instead of on line syntax: it subsumes every comment form at once and
   cannot be fooled by a `/*` inside a string, with an R32 assertion on the
   length-preservation invariant it rests on. Strictly monotone (it can only
   carry MORE preamble), and dedup_propagate is a byte-gate feeder, so a bug here
   can fail to bank but never falsely bank.

2. EXEMPLAR — the body also declared a draft-local `struct BigCopy164` tag, which
   the tool refuses by design (two macros defining one tag would redefine it in a
   single TU). The shared `struct BigCopy` (engine_types.h L312) is the identical
   layout and is ALREADY used this exact way at engine_core.h:16158, so switching
   the exemplar to it is byte-neutral and drops the alias too.

Probed on ONE member before scaling (R37/S29): byte-identical 9052dc0e first try;
then 138 overlays byte-identical.

PROPAGATE head accounting after this: 7,398 of 18,545 ins banked (func_80147364
4,110 + func_8012A598 3,288). Still open, each with a NAMED cause and none yet
diagnosed against a build: func_8012f274 (3,973, dropped), func_8016ba68 (3,886,
4/138), func_801466f0 (3,288, the S6b D4 wrapped-alias gap).
2026-08-03 23:53:50 -06:00
Drew T c7ad41c8a3 feat(phase-30 T6/S11): the propagation lag — EXTEND 31/36, and the PROPAGATE head measured
Continues the S11 lane. Fleet 96.01 -> 96.06% fn-count / 93.6 -> 93.7% instr /
88.0% distinct; dedup 1905 -> 1907 groups, 0 failed, C1 240669/240669.
R22 clean-fleet: 140 passed, 0 failed of 140. 0 NON_MATCHING (G4).

EXTEND (SC07): the 16 volatile-blocked DIFF slots banked on retry after the
data asm-label alias -> lane total 31/36.

PROPAGATE head, measured rather than projected. .run/s8_lag.json re-split: the
checkpoint's "45 classes / 20,837 ins" is really 5 classes carrying 18,545 ins
(89%) and 41 carrying 2,316. Per-class outcome:

  func_80147364  30x137 = 4,110  BANKED x137 (definition-side asm-label alias)
  func_8012f274  29x137 = 3,973  DROPPED — byte-diverges in ~130 overlays
  func_8016ba68  29x134 = 3,886  4 of 138 banked; excluded from ~130
  func_8012a598  24x137 = 3,288  SKIPPED, cause NAMED by the tool
  func_801466f0  24x137 = 3,288  no source found — the S6b D4 gap, still open

  func_80147364's byte-true definition is `(u16, u16)` while 4,046 fleet decls
  say `(u16, s32)`. u16 is a default-promotion type, so the `()` no-prototype
  escape is ILLEGAL (the documented gcc-2.7.2 dead-end) and conforming the decl
  would change caller codegen. The DEFINITION-SIDE asm-label alias gives the def
  a distinct C identifier while emitting the real symbol -- zero blast radius on
  every caller. Probed on ONE member first (1 build, not 137 -- the S29
  discipline): byte-identical 9052dc0e first try; then 137 overlays clean.
  In-tree precedent for the form: 1,725 files.

MEASURED NEGATIVE, recorded not buried: `dedup_propagate --recover` banked only
4 of 138 on func_8016ba68 and dropped func_8012f274 entirely (137 [exclude]
lines). The caller-extern reconcile that is 16/16 lifetime ON DRAFTS does NOT
transfer to PROPAGATION of these two. Cause not yet diagnosed -- probe one
excluded overlay's build output before any further attempt (§136a), do not
re-run the lever hoping.

NAMED NEXT (cheapest first): func_8012a598 skips on `missing file-scope extern
(CARRY-FIXABLE): D_801151D4, D_80126DB8_a, D_80127504` -- the SESSION-18
preamble-backscan class. Its body is 2 statements and `struct BigCopy` is
ALREADY in the shared engine_types.h (L312) with the identical statement already
macro-ized at engine_core.h:16158, so a hand-authored macro (the func_80147364
path) should take it x137 for ~0 tokens.

Process errors recorded in CURRENT_PHASE.md, all three one mechanism -- the
signal sampled is not the thing waited for: (1) a `nohup CMD &` wrapper's exit
read as the fleet check finishing (it stood at 63/140); (2) a corpus.stubs probe
mid-rebuild, which R32's coverage assertion refused rather than answer wrongly;
(3) CORRECTION to the S10 checkpoint's own rule -- `pgrep -x make` is right for
one make and WRONG for a campaign of sequential makes (it fired in a gap and
reported a live campaign done), and `pgrep -f <pattern>` SELF-MATCHES so that
waiter can never exit. Wait on the campaign process or `treelock.sh --status`.
2026-08-03 23:41:34 -06:00
Drew T 16a1dabc79 feat(phase-30 T6): SC07 EXTEND lane 0/36 -> 15 banked; the 4 "DIFF"s are a volatile decl
Banked 15 h_exact members into the 4 SC07 overlays via dedup_extend, and
diagnosed the class that dedup_extend's own header records as UNDIAGNOSED.

THE 4 DIFFs ARE NOT A CODEGEN WALL. dedup_extend's correctness argument says an
h_exact match guarantees byte-identity including relocs, so a DIFF should be
impossible. Both halves of that tension resolved against the bytes:

  1. The contract HOLDS. func_80162FF4's original bytes are sha1-identical in
     ov_SC07_006 and ov_SC01_000 (af1aceb2...), so the registry is not lying.
  2. The cause is TU CONTEXT. The SC07 host TU (_jr_8015C32C.c:1177) declares
     `extern volatile s32 D_80127090/94/98` at FILE scope; none of the 134
     working overlays' copy of that TU does. Volatile makes the macro's three
     stores a scheduling barrier, so `addu $a0,$s2,$zero` cannot sink into the
     `jal func_80146D30` delay slot -- the built body emits it early plus a nop,
     one instruction longer. Measured word-for-word against the payload:
       built  +0x090 addu / lui,sw x3 / jal / NOP
       ref    +0x090 lui,sw x3 / jal / addu-in-delay-slot
     All 4 DIFF macros touch exactly those 3 symbols, which is why all 4 fail in
     all 4 binaries and nowhere else.

  Fix: the §37/§124 DATA asm-label alias inside the 4 macros
  (`extern s32 aD_80127090 __asm__("D_80127090")`) -- a distinct C identifier is
  immune to any TU's declaration of the symbol, and is byte-neutral by
  construction in the other 134 (same symbol, same type, same non-volatile
  semantics). In-tree precedent: ov_SC06_008_jr_80135D20.c:1434.

R22 clean-fleet: make clean && extract-all && check-all -> 140 passed, 0 failed
of 140, with the 15 banks AND the alias edit in.

Remaining in this lane, both named not walled: func_80144B9C x4 (the whale --
its registry `func` field is a bare name, not a DEFINE_ macro, so write_drafts
emits a CALL; it needs the §38 -O0 shared-header route, and dedup_extend should
refuse-and-name it per R32) and func_80149954 x1 (blocked behind func_80147364,
whose u16 params make the `()` no-prototype escape illegal -- the documented
gcc-2.7.2 default-promotion dead-end; needs the alias or a de-macroize).
2026-08-03 22:57:51 -06:00
Drew T eb2e72328b fix(phase-30 T6): byte-neutral decl conforms unblock the SC07 EXTEND lane
The dedup_extend SC07 lane banked 0/36. Captured every failure's own compiler
error rather than guessing: 5 PLUMBING (declaration conflicts) + 4 DIFF per
binary, and the PLUMBING set reduces to 4 distinct symbols repeated across all
four binaries.

Fixed at the lowest available blast radius, each byte-neutral BY CONSTRUCTION
and proven by R22:

- func_80146C3C (8 of 36): T2, but 1 token. DEFINE_func_8016A08C /
  DEFINE_func_8016A1CC declared it `(void)` while the SC07 TUs declare
  `(u8 *a0)`. Both macros already CAST at the call site, so the prototype is
  codegen-irrelevant -> relax to `()` (no-prototype). Measured first: all 4,020
  fleet decls are (void)/()/(u8*)/(u8 *a0) — no default-promotion param
  anywhere, so `()` is compatible with every one of them (the gcc-2.7.2 `()`
  dead-end needs a promoting param; there is none).
- func_8014F4C0 (4 of 36, self-axis), D_80126CC4 (3), func_8012E5CC (1): T1
  binary-local. Conformed the SC07 decls to the fleet-canonical form. Every one
  has ZERO uncast uses in its TU (verified per file), so the decls were pure
  splat boilerplate with no codegen effect.

Deliberately NOT touched: engine_core.h beyond those 2 lines. The §29 law is
about BULK header edits (the 2,046-file sed that still didn't build); 2 targeted
macro lines with a measured compatibility argument is not that.

R22 clean-fleet: make clean && extract-all && check-all -> 140 passed, 0 failed
of 140. Enabling change only; no function banked in this commit.

Method note (mine, recorded): I read `corpus.stubs` while `make extract-all` was
mid-flight and got garbage — R32's coverage assertion refused to answer instead
of returning a wrong stub set. A measurement taken during a rebuild is not a
measurement (S27's law, re-earned). Also: `nohup CMD &` inside a backgrounded
Bash call makes the harness signal completion of the WRAPPER, not the campaign —
the R22 "finished" at 63/140. Waited on `pgrep -x make` instead.
2026-08-03 22:49:58 -06:00
Drew T ef1d8c9fab docs(phase-30): SESSION-31/32 checkpoint — fresh-session safe; Sonnet finding, 3 live lanes, stale P32 ledger flagged 2026-08-03 22:28:16 -06:00
Drew T 1859266d60 feat(phase-30 S10): Sonnet wave — 13 heads + 57 members; the §136i ~120 boundary is too LOW
- DREW'S CALL (2026-08-03): route the 30-target x2-9 wave to SONNET instead of Opus. The §136i
  >=120-ins Opus threshold was MY EXTRAPOLATION, never measured; this wave (125-793 ins) probes
  exactly the region where there was no data.
- RESULT: 13 banked of 16 that ran = **81%**, vs Opus's 10/13 = 77% on the comparable S8-3 slice.
  At least 8 banked SONNET-DIRECT (65 agents spawned: 60 sonnet, 5 opus escalations). Propagated
  57 member-matches / 4 failed across 42 overlays. 70 instances. R22 clean-fleet 140/140.
  FLEET 96.01% fn / 93.6% instr / 88.0% distinct (77,550 uniq).
  => **Sonnet is at least as capable as Opus on 125-793 ins. The ~120 boundary is too low.**
  NOT rewriting it to a specific number yet: 16 samples under a throttle confound cannot name a
  cliff. The controlled A/B (task #12) is how that number gets fixed properly.
- THE REAL LIMITER IS CAPACITY, NOT CAPABILITY: 14 of 30 agents were killed by SERVER-side
  throttling ("Server is temporarily limiting requests (not your usage limit)") that 30 concurrent
  Opus agents did not trigger. Practical rule: run Sonnet waves at ~12-16 concurrency, not 30.
  The 14 unrun targets are listed in the checkpoint for a smaller-batch retry.
- Sonnet's work quality was not shallow — three examples: func_8018797C read local-alloc.c and
  forced loads into an AGGREGATE to stop find_free_reg greedily taking 3 callee-saved regs;
  func_8018D870 used §136c sibling-first for ~70% of the body then blocked a coalesce with a pin;
  func_8017E3AC diagnosed an RC-3 callee-saved-order swap and noted the pin must be s32 or a stray
  `andi 0xffff` appears.
- MY ERROR, RECORDED: `until [ -s <output> ]` fires at the FIRST LINE of output, not at completion.
  It fired mid-propagation and I ran `make clean` on top of a live family_sweep, deleting asm/ and
  aborting both the regen and the sweep (corpus's R32 assertion refused to answer rather than return
  a wrong stub set — working as designed). No bad bytes: R22 verified 140/140 immediately after, and
  the propagation simply re-ran clean. Correct waiter is `pgrep -x make` (exact process name), which
  also cannot self-match the way `pgrep -f <pattern>` did when it leaked 4 waiter shells earlier.
  Third instance today of ONE root cause: trusting a proxy instead of the thing itself (a weight
  column vs a probe §136h; an exit status vs build output §136a; file-existence vs process exit).
2026-08-03 22:27:19 -06:00
Drew T cf10d28459 feat(phase-30 S9): x2-9 calibration wave — 22/25 banked + 67 members; the grind rate is MEASURED
- CALIBRATION (25 stratified targets: 12 head-by-weight + 13 sampled across the band, so the
  measurement captures the DECAY, not just the head): 28 agents -> 22 claimed -> gate BANKED 22/25
  (88%) -> propagated 67 member-matches / 13 failed across 38 overlays. 89 instances.
  **22,937 templatable instructions banked in one wave.**
    HEAD  9/12 -> 19,492 of 28,584 templ ins
    BODY 13/13 ->  3,445 of  3,445 templ ins   (the small ones are EASY; all 3 misses were 611-793 ins)
- FIRST SONNET DATA (§136i ladder's new middle rung): **Sonnet 6/6 · Haiku 6/6 · Opus 10/13.**
  The two cheap tiers went 12/12 and Opus absorbed every hard failure — consistent with correct
  size-routing rather than luck. Small n; the controlled A/B stays parked (task #12).
- THE PROJECTION for the >=95% instr bar (Drew's decision input): 411 of 1,872 families cover the
  212,594-instruction gap = ~19 waves optimistic, 20-30 realistic. Mean templ ins/family decays
  1,844 (top-25) -> 1,046 (top-100) -> 525 (top-400) -> 193 (band-wide), so early waves look like
  this one and later ones bank MORE functions for FEWER instructions.
- DECISION (Drew): NO phase close — keep grinding. Campaign tracked as task #15.
- Carried failures -> next lanes: func_8017D174 (793 ins, closeness 5 after ~90 variants; diagnosed
  a backward-scheduler priority race -> permuter, correctly NOT ledgered a wall), func_80186E24
  (611 ins, 133 of 139 diffs pure register numbers -> a natural §137 test), func_8017E2EC.
- §136c sibling-first paid again: func_8017DF84 (766 ins) MATCHED because a banked byte-matched twin
  existed in the same TU; its 697 index-diffs traced to ONE root cause (a bare 0xFFFFFF literal that
  loop.c hoisted to the OUTER preheader, stealing $s3) — closed by binding it to a local declared as
  the FIRST statement of the inner loop body. Verified via rtu_match (real-TU), not just match_one.
2026-08-03 19:06:02 -06:00
Drew T 1f9c1be858 docs(phase-30 S8): checkpoint — 167/167 banked, every high-multiplier lane spent; T5 is the next decision 2026-08-03 16:25:29 -06:00
Drew T a4bc49a23d feat(phase-30 S8): the x10-99 band closes 23/23; §137 makes REGALLOC-PERM arithmetic, not a permuter job
- S8-3 (23 fresh x10-99 families, 121-328 ins — the hardest band this session): draft 16/23 ->
  capture (1 PLUMBING / 6 DIFF) -> reconcile 1/1 -> redraft 6/6 => **23/23 (100%)**.
  Propagated 206 + 81 = 287 member-matches across 80+54 overlays. R22 clean-fleet 140/140.
  FLEET 95.97% fn / 93.4% instr / 87.5% distinct (77,404 uniq); dedup 1905/0; 0 NON_MATCHING.
- §136b CLOSES AT 15/15 — no function ledgered "genuine byte-DIFF" survived a redraft, all session.
- §137 (NEW, the session's most reusable result): REGALLOC-PERM — a clean 2-register swap — is a
  TWO-COMPILE ARITHMETIC PROBLEM. global.c:allocno_compare ranks by floor_log2(R)*R/L*1e4*size;
  read R and L out of `cc1 -dl -dg` for BOTH contenders AND their ranked neighbours to get the
  admissible priority WINDOW, then place a zero-byte `__asm__ __volatile__("" ::"r"(v))` so L lands
  inside it. func_801833F0: contenders ONE unit apart (1297 vs 1296), window (1228,1296), five
  placements probed, only L=219 -> pri 1232 worked. R and L are FORCED BY THE EMITTED CODE (L is
  recomputed post-sched1), which is exactly why source-reordering is a dead end for this class.
  Converts a class the permuter banked 0 from all session into a deterministic calculation.
  Companion: floor_log2 makes ref-count a STEP function (5/6/7 refs are worthless, you must reach 8)
  — func_8017EFA8 closed 30 register-name mismatches by taking a pseudo 4 refs -> 8 with a dead read.
- §136j — the failure MIX FLIPS WITH SIZE: <=120 ins fails ~70% on declarations; 121-328 ins fails
  86% on genuine codegen. Budget reconcile for the small band, redraft for the big one — and do NOT
  read 70% on a big-function wave as a broken pipeline; that is the expected shape.
- §137a — a gate verdict has a TIMESTAMP. Two "DIFF" ledger entries were STALE (draft rewritten 28
  min after the gate ran, never re-gated); both were already byte-perfect. Compare verdict time to
  draft mtime before redrafting. Plus two offline oracles an agent built: a FULL RELOCATION RESOLVE
  (catches wrong jal/%hi/%lo targets that match_one's mask hides) and a COLLATERAL CHECK (whole-TU
  objdump with/without splice). Together they discriminate all three causes of "match_one says MATCH
  but the overlay SHA differs" without running make.
- §136f addendum — the collider is often an already-banked SIBLING BELOW the splice; locate it by
  arithmetic (draft grows the file N lines, so TU line L reports at L+N).
- cookbook-index 380 -> 382 sections.
2026-08-03 16:25:06 -06:00
Drew T 18fc50d0f8 docs(phase-30): §136i — insert SONNET between Haiku and Opus in the drafter ladder (Drew 2026-08-03)
- MEASURED BASIS (P30 S7, 144-target campaign): the two-tier rule from the 2026-06-29 A/B left the
  ~50-120-ins band unassigned, and every wave since defaulted it to Haiku-with-Opus-escalation.
  Haiku-direct banked 3/8 on that band while Opus-escalation-after-a-Haiku-miss banked 10/11 — i.e.
  Haiku was acting as EXPENSIVE TRIAGE (a wasted draft + a full Opus redraft), not a cheap drafter.
  The original A/B only proved parity <=52 ins; everything above that was extrapolation.
- LADDER: haiku <=~50 ins · SONNET ~50-120 · opus >=~120 or escalation · fable5 for a genuinely NEW
  wall class only. Never haiku->opus directly; never default a whole wave to opus because the band
  "looks hard" (the same extrapolation in the other direction).
- WIRED, not just documented: s7_manifest.py routes by the new thresholds; s7_wave4b.js escalates
  haiku->sonnet->opus instead of haiku->opus, and its meta/prose say so.
- Boundaries (~50/~120) are current best estimates — re-measure per-tier from the journal + the gate,
  never from the workflow's by_tier (it counts claims, not banks — §136).
- Byte-gate remains the sole arbiter, so a weaker drafter is a throughput risk, never a correctness
  risk (G3/P9). cookbook-index 378 -> 379.
2026-08-03 14:28:30 -06:00
Drew T e8a57b13fa docs(phase-30 S8): CORRECTION §136h — the zero-crack pool is residue, not a lever (1 bank / 1,781); my R37 violation 2026-08-03 13:29:33 -06:00
Drew T 2210ff6509 docs(phase-30 S7): checkpoint — B-shape queue closed 144/144; the zero-crack pool refills itself (120->147 families) 2026-08-03 13:03:13 -06:00
Drew T 1b8f26113c feat(phase-30 S7): close the B-shape queue — 144/144 drafts banked; §136b closes 9/9
- FINAL LANES: reconcile ×5 (5/5) + redraft ×1 (1/1) -> gate BANKED 6/6 -> propagated 50 members
  across 28 overlays. **ALL 144 DRAFTED TARGETS BANKED (100%); zero stubs remain in the queue.**
  R22 clean-fleet 140/140 (seventh time this session).
  FLEET 95.88% fn / 92.9% instr / 86.5% distinct (77,106 unique fns); dedup 1905/0; 0 NON_MATCHING.
- LANE RECORDS: reconcile 15/15 lifetime · redraft 9/9 · §136b closes at 9 FOR 9 (every function
  ever ledgered "genuine byte-DIFF" banked on redraft).
- THE CAPTURE CLASSIFIER, third and final defect (§136a): it decided PLUMBING by matching a regex
  against cc1's PROSE, and cc1's vocabulary is open-ended — `too many arguments to function` matched
  nothing, so a trivially reconcilable function sat UNKNOWN through two gate rounds. Now DERIVES the
  class from the closed invariant (did the compile produce an object: `make ... Error N` +
  `Deleting file`). Re-running it moved 5 PLUMBING / 1 UNKNOWN -> 5 PLUMBING / 1 DIFF, and BOTH
  reclassified functions then banked. Three defects in one small tool in one session — an
  unreachable exit-status branch, a missed phrasing, and the prose-matching design behind both —
  each SILENTLY MIS-ROUTING REAL WORK. R33 in one line: if an invariant answers it, never re-parse.
- §136f — two declaration sub-cases: (1) a symbol you call may be DEFINED, not just declared, BELOW
  your splice point (func_8017D540 is defined 275 lines below as int(int); the draft guessed
  void(s32) from a bare jal); (2) an ARITY clash on the symbol you are DEFINING cannot be fixed by a
  cast — use the §37/§124 asm-label alias (func_801848DC; in-TU precedent at :8872).
- §136g — TWO INDEX ROUTINGS BYTE-REFUTED (func_801863B4). The index sends BRANCH-POLARITY to §3-T4
  (invert) and §34 (zero-byte fence); the agent tested BOTH at zero, read the gcc-2.7.2 source, and
  found jump.c:1806 `if (foo) bar; else break` range-swap — which runs long BEFORE reorg, so a fence
  CANNOT block it. Real lever: put a label between the if-join and the return label (wrap the loop
  in the guard). Also: same-address lh+lhu is MIPS LOAD_EXTEND_OP==ZERO_EXTEND (mips.h:1163), and
  combine collapses the pair unless the HImode pseudo has two reaching defs.
  REFUTED ROUTINGS ARE RECORDED NEXT TO THE CORRECT ONE — otherwise the next agent re-runs them.
- cookbook-index 375 -> 377 sections (§136 .. §136g earned this session).
2026-08-03 13:02:29 -06:00
Drew T b61d805b8b feat(phase-30 S7): wave 4b batch 3 — 35 heads + 305 members; the 144-family B-shape queue is worked
- BATCH 3 (37 targets, 41 agents, 2.75M tok -> 35 claimed): gate BANKED 35; family_sweep propagated
  305 member-matches / 39 failed across 77 overlays (14 STRUCT skipped by design). 340 instances.
  R22 clean-fleet 140/140 (sixth time this session).
  FLEET 95.86% fn / 92.9% instr / 86.5% distinct (77,061 unique fns); dedup 1905/0; 0 NON_MATCHING.
- WAVE 4b COMPLETE: b1 32/37 + b2 35/37 + b3 35/37; with wave 4a (30/33) the whole 144-family
  B-shape queue that opened this session is worked through — 138 of 144 drafts banked (96%).
- §136e — batch 3's two HONEST NEGATIVES, worth as much as the wins:
  (1) §136c SIBLING-FIRST HAS A PRECONDITION. func_801899AC's family has all 13 members still
      unmatched and no engine_core.h twin, so there IS no byte-verified sibling and the search is
      pure cost. Check a banked sibling EXISTS before spending the greps.
  (2) A loop increment in the loop-back DELAY SLOT + a compensating negative addiu is a SOURCE
      SHAPE, not a reorg artefact — MIPS1 has no annulling, so reorg CANNOT invent the
      compensation. Write `p += 2; if (t == cur) break; ... p -= 2;`. combine's reg_n_sets==1 guard
      stops the addiu folding into the following lw. The index's delay-slot entries point at reorg,
      which is a dead end for this class.
  Plus a new §136-L1 application on the RETURN axis (an over-scoped temp became a global allocno and
  swapped $v0/$v1 with the returned local, collapsing the target's `j` + `addu` return).
- COMPOSITION, demonstrated on func_8017D5F4 (46 ins): flat early-returns -> dead-local frame pad ->
  s16 locals -> operand order -> 3 register pins -> 2 zero-byte re-ties -> permuter for the last 2.
  THE PERMUTER IS THE LAST STEP ON AN ALREADY-PINNED BASE, not the first.
- cookbook-index 374 -> 375 sections. 6 stubs remain; per §136b none is a wall on one attempt.
2026-08-03 12:34:53 -06:00