Commit Graph

961 Commits

Author SHA1 Message Date
Drew T 02e1b3a7e6 feat(waves): every pack now carries that function's own PAST-ATTEMPT history
tools/journal_notes.py mines the agent journals per (binary, fn) and appends a
PAST ATTEMPTS section to the pack; claude_wave_packs.py calls it automatically, so
it is the default rather than a step to remember. Idempotent, and R48-safe (a note
stamped with a different binary is never served — §238 homonyms).

Measured before adopting (S71 wave 1, 50 one-agent workflows over the 210-function
real frontier where every target had already refused an earlier wave):
  * 38/39 MATCH at closeness 0 (97.4%) vs S70's 124/131 (94.7%) on an EASIER pool
  * 29/39 agents cite a prior attempt as what they used
  * 4/39 banked by RECOVERING a body that already matched, from a path a note named
  * 11/39 matched on the first compile

The two costs it removes are re-testing a measured-inert lever (§406 lists twelve,
§407 fifteen, §410 four — each paid for by an agent and never seen again) and
re-deriving a body that already exists on disk.

Also: jr_isolate_all places file-local `static` definitions with the region that uses
them instead of refusing the whole file. A `static inline` helper (§82.1) has no
address by construction, which is not a defect; the R32 guard was refusing these and
blocking the isolate on 4 of the 6 overlays whose CARVE-REFUSED functions it is the
named remedy for. Two regions using one static is still a hard refusal (duplicating a
used static is a byte change, R43).

docs: cookbook §411, wave-playbook step 3b, accelerators entry.
2026-09-02 01:11:52 -06:00
Drew T 89c3cf831b docs(phase-31): S71 wave 1 — journal-fuelled packs, 100% first-pass MATCH; cookbook 1078
* Every pack carried PAST ATTEMPTS ON THIS EXACT FUNCTION, mined per-function from the
  historical agent journals (52 of 60 targets, 131 notes). Every landed agent returned
  MATCH at closeness 0 on the hardest frontier we have.
* §409 — the wave and the nine laws it produced. Law 1: a relocation-stream
  TRANSPOSITION is invisible to match_one, the permuter scorer and every similarity
  tier (HI16/LO16 masking; the §195-D blind spot for a different reloc class), and it
  retroactively explains "MATCH but the gate rejected it" verdicts.
* §410 — COPY THEN ACCUMULATE ON THE COPY: satisfies the $s2 in-place destination and
  the sched1 birthing boost at once, with the agent's measured refutation list.
2026-09-02 01:04:27 -06:00
Drew T 698f2959ae fix(campaign): R48 — reloc_filter resolves a draft's binary per-draft, not by bare name
* `binof = {c["fn"]: c["binary"]}` was last-writer-wins, and `status`, `det` and `subof`
  had the same shape — a draft of a name carried by two binaries was stamped with
  whichever card came last and then reloc-checked against the OTHER binary's symbols.
* Resolve per draft instead: the shard's own target list first
  (`.run/wave_<tag>_targets.<i>.json` = `targets[i::workers]`, each row carrying its
  binary), a unique-name card second, a counted refusal when neither can answer (R43).
* R39 negative control over every historical wave: 42,655 drafts, 0 regressions,
  2,317 (5.4%) previously mis-stamped; 2,107 homonym card names fleet-wide.
  Intra-shard ambiguity: 0 of 50,684 (shard, name) pairs over 302,370 shard files.

docs: §408 — §406 refuted as a sweep (0 MATCH / 14 applied, 0 / 210). The 134-member
census counted main's 960 LINKED library stubs and matched a symmetric SHAPE; derived
from the mine-vs-target residual the addressable set is 15 / 210. Decision-log entry
records the pivot: 64 of 210 (30.5%) already match standalone, so the frontier's
largest lane is §376 integration, not codegen.

tools/weave_sweep.py — the derived-selector sweep (R32 coverage, R41 denominators,
--lever-all ablation control).
2026-09-02 00:19:59 -06:00
Drew T 1632c6adec docs(phase-31): S70 FINAL-4 — 145 banked (355->210), 115/118 wave MATCH, 5 card defects (3 fixed), cookbook 1074 2026-09-01 23:40:28 -06:00
Drew T 2740f18373 docs(cookbook): §407 late-wave addenda — reorg delay-slot refusal, find_best_addr folding, and the empty-corpus scan caution 2026-09-01 23:27:21 -06:00
Drew T f83443ecdc docs(cookbook): §405 the S70 wave harvest (113 MATCH / 130 agents) + §406 the 134-function prologue-weave sweep
§405 — the generalisable residue of three waves, grouped by lever family:
  A. match_one compares .text ONLY, so a switch's jump table is invisible to it —
     a draft can score 110/110 with a PERMUTED table emitted as identity
     (resident/func_800D02D0, byte-witnessed). Some historical 'MATCH but gate
     rejected' verdicts were the ORACLE being wrong (R34 in our most-trusted tool).
  B. the scheduler dials, incl. the birthing-boost re-tie's PLACEMENT rule (must be
     a LATER basic block) and reorg's stop_search_p halting at any asm.
  C. regalloc from C without pins: variable identity picks global- vs local-alloc;
     a cross-arm join value loses first-fit and should be duplicated per arm for
     cross_jump to refund; pass-through params reserve arg regs at zero cost.
  D. integration is still the bottleneck — ~1/3 had byte-correct bodies blocked
     only by declarations; the TU is the authority.
  E. what the agents REFUTED: §137 invariance is false for CONFLICT-driven ties;
     §153's 'cse2 puts it back' fails for the dead-def case; §257-8 volatility
     polarity is per-site, not portable.

§406 — the prologue-weave class: 134 of 1,237 open stubs (11%) share the
sw  / move , / sw  shape, cause traced in cc1's .i.sched2 dump
(memrefs_conflict_p finds no dependence, potential_hazard picks sw $ra early), 12
variants measured inert, and ONE working lever (non-volatile memory-clobber asm
after the param copy). One lever x 134 known targets = a sweep, not an idiom.
2026-09-01 23:19:52 -06:00
Drew T f33c455747 docs(playbook): fix the packs invocation — the old form hid SYS.md from every drafting agent
claude_wave_packs writes out_dir/SYS.md + out_dir/packs/<fn>.md, so out_dir is the
WAVE dir. The playbook documented  plus an mv to undo the
resulting packs/packs nesting — which also put SYS.md at <wave>/packs/SYS.md while
claude_wave_draft.js tells every agent to read <wave>/SYS.md.

Net effect: the laws file did not exist where any agent looked, in every wave run
this way, and the brief silently degraded to the pack alone. Two S70 agents said so
verbatim; the rest never noticed. Passing the wave dir fixes it and removes the mv.
2026-09-01 22:55:19 -06:00
Drew T 64dc914afe chore(report): refresh digests after the §332b banks 2026-09-01 20:46:09 -06:00
Drew T db22b69081 docs(cookbook): correct §404 — harvest_verify DOES persist; the lost bank was my own git checkout 2026-09-01 20:36:41 -06:00
Drew T 9b57eaa2f0 chore(report): refresh digests after the S70 twin banks 2026-09-01 17:48:01 -06:00
Drew T cdac7502f9 docs(cookbook): §404 — harvest_verify verifies but does not bank; gate_stage persists 2026-09-01 17:42:44 -06:00
Drew T 957d0a822a docs(cookbook): §403 — record the shipped refusal + its negative control 2026-09-01 17:38:54 -06:00
Drew T 2fbf93d2e0 chore(report): refresh backlog + fleet progress after the S70 banks 2026-09-01 17:30:02 -06:00
Drew T 062ac7d100 docs(cookbook): §401 jtbl-carve probe blind spot · §402 path-resolved-in-another-cwd · §403 undo-journal keyed by name 2026-09-01 17:20:28 -06:00
Drew T 21372a2348 docs(decision-log): R31 — the S70 postgame reframe (tools scope to the CRACKED corpus, not the frontier) 2026-09-01 16:08:16 -06:00
Drew T 49f27f2293 chore(report): refresh backlog + fleet progress after the S69 banks 2026-09-01 15:45:46 -06:00
Drew T 20f80fd933 docs: §400 + SETUP + carve-state memory for the new-file adoption fix; correct a stale docstring
§400 — a baseline check that conflates "absent everywhere" with "changed under
us" silently drops new files. The general law: when a comparison uses two
different sentinels for "nothing" ("" from a failed command, None from a missing
file), it reports a difference that does not exist — and in a GUARD, a phantom
difference becomes a refusal, which looks exactly like the guard working.

Corollary recorded in both §400 and the carve-state memory: "never blanket-add"
covers SHARED carve state (overlays.mk, splat yamls). It does NOT cover a carve's
own new per-binary source file, which is named by a committed yaml and whose 31
siblings are tracked — that one must be adopted with the bank that created it.

Docstring correction: parallel_gate does NOT use `git add -u src/` (that is
gate_stage's form); it adds exactly the adopted paths. My first diagnosis of this
bug blamed `-u` on the strength of that stale line and was WRONG — the cause was
the baseline comparison. Noted in the docstring so the next reader is not
misdirected the same way.
2026-09-01 15:33:04 -06:00
Drew T 4cf531beea docs(cookbook): §399 — four levers from the final S69 round, harvested late
Caught by Drew asking whether the last waves were harvested. They were not: I
banked 1 of 5 (§398b) and left four lever sets in the notifications. Also found
two paid-for MATCHes that were never staged or gated.

(a) a fence BETWEEN two prologue loads, where source reorder does nothing —
    the order is fixed before statement order matters (md_MAIN_013/func_800CB56C)
(b) SINK a call into BOTH arms and let cross_jump keep only the jal suffix;
    88ins/close86 -> 92/13, then §3-T2 field order let each sh $zero fill an lhu
    load-delay. Duplicate in source so the compiler merges, rather than writing
    the merged form yourself (ov_SC07_001/func_8017EDC0)
(c) a $v0->$a0->$s3 DOUBLE COPY is a two-pseudo tell: SImode temp for the compare
    + separate HImode var for the tail (70->37); plus §195-N precondition 5 —
    nesting `return 1` with ONE trailing `return 0` blocks jump.c's store-flag
    transform so reorg fills both delay slots (18->0) (ov_SC02_017/func_8018347C)
(d) the re-tie as a BIV KILLER: a second set makes n_times_set>1 so loop.c
    refuses the pseudo as a biv, killing the combined address giv. volatile was
    worse, a dead read did nothing (ov_SC07_001/func_8017E4DC)

(d) makes THREE distinct uses of the zero-byte re-tie in one session — §380
un-hoists a move_movables invariant, §393 kills the scheduler's birthing boost,
§399d denies a biv. One line, three passes: when a single-set pseudo is being
treated specially, give it a second set.
2026-09-01 15:18:40 -06:00
Drew T 8a19b3ca52 docs(cookbook): §398b — naming a sub-expression changes which pseudo survives; inline it at both use sites 2026-09-01 15:01:06 -06:00
Drew T 65f5ac61ac docs(cookbook): §398 — family_remap carries the SOURCE TU's decl environment; a remap is a draft, not a bank
Measured: 22 twin remaps gated as a batch -> 3 banked, 11 CC1-FAIL/PLUMBING, 8
DIFF. The eleven integration failures read 'syntax error before', 'undeclared',
'conflicting types', 'parse error' — the signature of a decl block written for
another TU.

family_remap rewrites the BODY correctly (per-overlay symbols, reloc targets) but
carries the source TU's typedefs/externs/callee prototypes verbatim into a
destination that already owns those names — §378c's fifth variant, at scale and by
construction. The 8 DIFFs are the h_norm class being 80%, not 100%.

Planning consequence (R41): the remap lane's realistic yield is ~15% straight
through and ~50% after the integration pass, NOT the 76-88% PURE-class rate.
Quote the straight-through number.

Tooling gap named: family_remap should emit the body with the DESTINATION TU's
decl environment; decl_prior already computes it for cards, and
cast_self_callers/fix_arity_callers already edit it.
2026-09-01 14:55:47 -06:00
Drew T 8f171c6ce6 feat(tools): verify_binary + twin_rescan — put S69's two habits in the tooling, not in prose
Both rules were already written down (§384, §397) and both were violated anyway,
which is the argument for a tool: a habit you must remember at the moment you are
impatient is not a control.

tools/verify_binary.py — ALWAYS re-extracts before building, because a carve
rewrites splat inputs and a build over stale extract state produces a meaningless
SHA. S69 read three binaries as red on build-only checks; all three were
BYTE-IDENTICAL after extract+build, and two false reds cost legitimate work that
had to be restored (a 96-line match, and 23 declaration edits). --all-touched
sweeps everything with uncommitted src/ or config/ changes.

tools/twin_rescan.py — the twin oracle answers "is there a BANKED body like
this?", so an OPEN-OPEN cluster correctly reports "no banked twin" for every
member and that verdict is stale the instant one banks. Diffs the scan against
the previous snapshot so it reports what JUST became free, not the whole board,
with the ready-to-run family_remap command per row. Baseline: 318 open stubs, 37
already carry a banked twin at d<=5.

Memories added: rescan-twins-after-every-bank, check-against-a-known-true-case.
2026-09-01 14:50:26 -06:00
Drew T 9d01e382cc docs: §397 + playbook §2a-3 — re-run the twin scan after every exemplar bank
Measured the expensive way. A reach-6 cluster showed open-open, so seed_ref
correctly reported 'no banked twin' for all six. I cracked the exemplar (203k
tokens, five new levers) and then drafted four siblings at ~60k each — including
one that had already burned 257k plateauing at permuter-class NEAR.

They were EXACT clones. The agents' own diffs said so: 'label-stripped .s diff vs
the twin is EMPTY', 'an EXACT clone (asm diff = labels only)'. The moment the
exemplar banked, seed_ref returned it as a banked twin for every sibling, and
family_remap + the §378 chain banks them for ~0 tokens.

The law: a bank CHANGES THE TWIN GRAPH. The twin oracle answers 'is there a
BANKED body like this?', so its verdict for every sibling is stale the instant the
exemplar lands. crack-wave-sweep-map-regen applied one level down — the family map
is not the only stale artifact, and the twin oracle is the one the cards read.

Also: never draft two members of one cluster in parallel; if either cracks the
other is free.
2026-09-01 14:37:18 -06:00
Drew T 8f4f629b4d docs(cookbook): §396 — six levers from the S69 singleton round (COND_EXPR corroborated independently) 2026-09-01 14:31:08 -06:00
Drew T 860f866f6e docs: §322b/§332b/§378c + accelerator #19 + SETUP — the Fable-3 blocked-pile audit
§322b — the carve class is COMPLETABLE, and every worktree CARVE-REFUSED was an
instrument verdict (.run/sig.<b>.jsonl is gitignored, absent from worktrees, so
jr_inventory read every carve as UNOWNED). build_carve's refusal is EXACT, not
conservative — one object emits one contiguous .rodata — and the real fix
(isolate into its own subseg) already exists and harvest_verify already runs it.
Live census: 71 non-contiguous of 123 jtbl stubs; 21 of those are twins of
already-banked bodies (3,852 ins) free at ~25s each. End-to-end byte-proven in
23 seconds. Remaining blockers are 18 overlay_src_split plumbing defects (<=30
lines each) plus a jr_isolate_all port for main.

§332b — the §332 "walls" are a per-OBJECT assembler mode, not a C limit. A 3-line
maspsx reorder-passthrough + as -O2 is byte-INERT across the whole 800c3/800c2
objects and yields 0 diffs for SIX walls whose drafts already exist. That turns
"permanently unbankable" into a per-object Makefile switch and retires
oracle_reorder.py. Only 13 of the 15 listed walls are even reachable.

§378c — a FIFTH decl-blocker variant: the DRAFT redeclares a type/data/callee the
TU or a header already owns. Fix the draft to the TU's spelling (§367), never the
reverse. Two "integration-blocked" rows were phantoms, one of them my own
--any-proto pre-pass breaking a sibling TU (variant 4, second bite).

accelerators #19 — a verdict recorded inside an isolated environment describes the
ENVIRONMENT. Isolation exists so the worker sees less; every gitignored input is a
difference it cannot distinguish from a genuine rejection, and it writes that
difference down once per function. Negative-control the environment with a
known-good item; assert the worker's inputs; report a missing input as MISSING,
never as a verdict.
2026-09-01 14:12:59 -06:00
Drew T 2f916b269d docs(cookbook): §395 — five narrowing/placement levers from the reach-6 exemplar crack 2026-09-01 13:57:34 -06:00
Drew T f8e522ea0d docs(cookbook): §378b — the four decl-blocker variants, and the two places §378 does NOT apply
Correcting my own guidance from earlier today. §378 gave the self-caller chain;
three more variants appeared within hours and two of them BREAK the chain.

Variant 3 (NEW, byte-proven ov_SC04_018/func_8017F35C, banked): conflicting
RETURN type on a decl that is ALREADY no-proto, where the symbol is
ADDRESS-TAKEN rather than called. --any-proto has nothing to relax and
cast_self_callers has no call site to cast; --sync-decls ALONE fixes it, and is
safe precisely because an address-taken site has no arguments to convert.

Variant 4 (REFUTATION of what I wrote in the playbook this morning): "run the
same chain on the callee the diagnostic names" is wrong at scale. Applied to
func_8012AD44 in ov_SC07_000 it no-protoed 60 caller decls and the binary went
RED (265b24bb vs 9dbe4241); reverted via journal. The self case is safe because
step 2 casts the call sites so the decl change cannot alter argument conversion;
for a callee, cast_self_callers correctly refuses and the decl change runs
unprotected. It banked main/func_80021D38 only because that callee had ONE decl,
not sixty.

Rule added: never --any-proto a symbol whose call sites you are not also casting;
count the sites first. The chain is a DECISION TABLE, not a sequence to run
blindly.
2026-09-01 13:34:21 -06:00
Drew T 34249a4696 docs(cookbook): §392-§394 — harvest the 7 sonnet overlay waves (105 agents, 57 MATCHes)
The hard gate caught me: m1/m2 (§379-§383) and the fable escalation (§385-§388)
were harvested, but o1-o4 and p1-p3 were not — 57 MATCH notes sat unbanked while
I was about to draw new waves.

§392 — seven byte-proven spelling levers, each of which closed a match on its own:
  (a) a same-address dual-sign read is fixed by ORDER (emit the unsigned
      store-source read first); cse merges lh/lhu for every cast spelling tried
  (b) a narrow temp picks the narrow load — s16 vs s32 decides lh vs lhu, and a
      signed decrement temp yields "sll 16" where unsigned yields "andi 0xFFFF"
  (c) tbl[idx-2] folds -8 into the lw offset; hoisting the subtract forces addiu
  (d) identical switch arms must be SEPARATE case blocks — the target duplicates
      arg setup per case and cross-jump-merges only the shared tail
  (e) distinct pseudos per repeated inline copy — one shared pair biases sched1's
      tie-break for the first copy only
  (f) split the widen into two statements to move the sll off a pinned register
  (g) the RETURN TYPE alone closed a 7-ins schedule residual (s32 -> void)

§393 — the BIRTHING BOOST: a single-set local gets max scheduling priority and
sched2's backward pass pushes it LATE; a zero-byte re-tie gives it a second set
and kills the boost. The scheduler-side sibling of §380 — same trick, different
pass, opposite symptom.

§394 — two align-1 accesses in one function reserve a phantom 8-byte stack slot;
a frame 8 bytes too large with no spill to account for it is the tell.
2026-09-01 13:14:55 -06:00
Drew T f11bf13b4f feat(seed_ref): the CONTAINED tier + docs for the twin ladder (§390/§391, accelerator #18)
tools/seed_ref.py gains --contained/--contained-control: an open stub that is a
banked body plus or minus WHOLE BLOCKS — the class edit distance ranks badly.
Branch-offset masking was required (unmasked offsets veto exactly the target
pairs) and a min-side-25 floor (89% of raw hits were prologue/epilogue vacuity).
Ranks by (substitutions+regions, cover), not by d. Controls: planted-deletion
positive 60/60, random-pair base rate 0/397, R32 population 346/346, and a
post-refactor --near regression reproducing the stored slice exactly.

Banked on first use: ov_SC01_077/func_80184D50 = banked ov_SC03_007/func_8018283C
minus its trailing `&= 0x7FFFFFFF;` — MATCH, closeness 0, 98/98.

* cookbook §390: minimum distance is not minimum work (rank by effort; a deletion
  is free, a substitution is thought), the lookalike filter r = d/min(nins) ~ 0.3
  (17 of 30 "cousins" were boilerplate coincidence), and the three fleet-wide
  nulls that close the scanner question — 0 new / 9 / 2. Spend integration
  effort, not scanner effort.
* cookbook §391: a byte-aligned struct copies in FOUR instructions (lwl/lwr/swl/
  swr), a word-aligned one in TWO. Never invent an aggregate type to make a draft
  compile — an invented word-aligned Blk8 lost exactly 8 ins across two copies and
  read as a believable "near, closeness 70" codegen residual.
* accelerators #18: a claim derived from BYTES is not a claim verified by a
  COMPILER. Every similarity/correctness claim must name the tier it reached
  (stream containment / compiled standalone / whole-binary gate / clean fleet);
  a report that says "verified" without one invites the strongest reading.
  Non-reproduction is a finding — say so rather than assuming your own setup.
* playbook §2a-2: the twin ladder (exact -> RELOC-ONLY -> CONTAINED -> cousin ->
  cold), take the cheapest tier available, widen only when the tier above is empty.
* SETUP inventory row; generic-decomp-package: rank by work, and stop building
  scanners once the well is dry.
2026-09-01 13:06:27 -06:00
Drew T 881dd5a37c docs: the NEAR-TWIN BAND — §389, accelerator #17, SETUP, playbook §2a, generic-decomp-package
The exact-hash twin tier found 22 of 352 reachable open stubs (6%). The
edit-distance band added by `seed_ref --near` finds 75 of 352 (21%) — 3.4x — on a
corpus we believed fully mined. 31 of the new rows were PURE reloc-only twins of
already-banked bodies; 8 banked the same day at ~0 agent tokens, one 94-ins
exemplar serving five open copies.

* cookbook §389: the h_norm hole (norm_stream drops its pending lui-hi on an
  intervening R-type, so indexed-global reloc twins hash differently and vanish
  from seed_ref/twin_sweep/dedup/family-maps at once). Do NOT fix h_norm — every
  stored calibration keys on it; the near tier reads through it.
* accelerators #17: the generalisable law. A similarity hash built for DEDUP
  under-matches by design, which is correct for dedup and silently lossy as a
  FRONTIER join — the two questions want opposite error directions, and the
  frontier failure looks exactly like "this function is unique".
* generic-decomp-package §2b: build the near band at the same time as the exact
  tier, with the three verifications. It pays from the first bank for a new
  project, where we paid a session to recover the debt.
* SETUP inventory row + playbook §2a (run it before believing any "no twin"
  verdict; never send a RELOC-ONLY row to a drafting agent).
2026-09-01 12:20:59 -06:00
Drew T 9d7b26523c docs: cookbook §384 — a carve-config bank is red until you re-extract; correct the S69 checkpoint
The 'false bank' in the S69 checkpoint was not one. Both instances verify
byte-identical after 'make extract BINARY=<b>'. §384 states the law (verification
must regenerate whatever the gate changed the inputs to), the trap inside it (a
src-only revert of a carve commit produces 'table-count drift vs the carve', which
reads like progress), and the give-away I ignored — the commit diffstat showed
config/overlays.mk and a splat yaml sitting next to the .c.
2026-09-01 11:09:31 -06:00
Drew T 9fc27960e9 feat(integration): teach the rest of the toolkit about §378 (self-caller cast)
The lever existed but nothing downstream applied it. Proof it mattered: a wave
agent this session diagnosed its own blocker as "§378 THE SELF-CALLER CAST, a
TU-level fix (cast_self_callers.py) that requires editing src/, which I'm not
permitted to touch" — the knowledge propagated, the automation did not.

* recover_integration.py: NEW "self-cast" stage (tier=binary), so the driver can
  run the whole chain as --stages arity,self-cast. The docstring states WHY the
  order is not arbitrary: self-cast answers the error that "arity" CREATES.
* residual_rules_b.py: both decl-conflict tiers now prescribe the full chain
  instead of "route to integration / budget for banking", and
  NOCOMPILE-UNDECLARED-FIXED now says outright NOT to gate the autodecl arm (it
  is a second conflicting declaration in the real TU).
* wave-playbook §4b: replaced the stale two-step recipe with the three-step
  chain, the one-driver form, the callee variant, and the MANDATORY
  --undo-journal.
* SETUP.md: full inventory row (R21) — it had zero mentions.

Not wired, deliberately: gate_stage's ladder rewrites DRAFTS via _xform, while
this edits the TU; a src-side edit inside the automatic gate needs
revert-on-failure, which recover_integration already owns.

Still open: a draft_prechecks rule to catch the self-decl conflict statically,
before a build is spent. The new stage's plumbing is verified (CLI + candidate
selection); its functional end-to-end run is NOT — gate12 held the tree.
2026-09-01 11:03:06 -06:00
Drew T 05195783b9 docs: mark the triage-ladder spec BUILT with its three corrections; accelerator #16
next-session-triage-ladder.md was still written as a to-build spec. It now leads
with the shipped status, the acceptance numbers, and the three things the spec got
wrong (the '32 free banks' were 0/28; the autodecl arm is worse in-tree than the
raw draft; PRE and POST cannot be the same pass because residual_rules_b needs a
draft), plus the one found by building it — never classify on a moving tree.

accelerators #16: a 'verified, just bank it' claim must name the compilation it
survived. Day-one kit material for a new decomp: any per-function oracle compiles
in isolation, every real bank compiles in context.
2026-09-01 03:49:21 -06:00
Drew T 1dd15eda32 feat(triage): the triage ladder — built, wired, and acceptance-green
tools/triage_ladder.py — the zero-token pre-agent pass, split PRE (target-side:
BANKED/WALL-332/PARKED, no build) from POST (residual_rules_b, needs a draft).
--escalate refuses a walled or banked target; --acceptance is the R39/R32 harness.
Refuses on a non-quiescent tree: a merging gate makes the stub oracle wrong in
both directions (measured, ov_SC01_004:func_8017EB30).

Acceptance, on the whole corpus: false-skip 0/1367 open stubs, recall 426/426
matched, wall tier fires on exactly the 10 enumerated walls (0 extra, 0 missing).
The first wall control asked for evidence that CANNOT exist — it scanned banked
functions' .s, which splat never writes — and printed '0 scanned / 0 tripped',
indistinguishable from a pass. The R32 empty-denominator assertion caught it on
its first run; replaced with a two-sided sweep over all open stubs.

tools/cast_self_callers.py — the §378 lever + --sync-decls for the narrow-param
case C89 forbids no-proto from reaching (§378a).

Wiring: wave_args drops walled/parked targets at draw time via pre_classify (one
implementation, R33); escalate_fable.js refuses any target without triage:'DRAFT'.

Tool fixes found by measurement:
* fix_arity_callers was blind to main entirely (globbed src/main/main*.c; main is
  src/*.c) — reported success over an empty file set through three gates. Now
  refuses when --binary selects no files.
* parallel_gate records each worker's 'failed by class' line (was truncated out of
  the 200-char tail); gater_lane retries in-tree ONLY on the diagnostic-free
  blind-worktree signature — S69 ran 22 serial retries against real cc1 errors.

docs: cookbook §376/§377/§378 (index 1033), SETUP.md, wave-playbook §4b.
2026-08-31 23:53:50 -06:00
Drew T a22d5646f6 docs(cookbook): §374/§375 — two more bounds on the register-pin lever
§374 a register __asm__($30) reservation is NOT honoured by move_movables under
pressure, and the corruption is SILENT (the build succeeds) -- audit the raw
objdump register uses before trusting a pinned build that compiles.
§375 an $a0-$a3 pin used LATE relocates an EARLIER outgoing-call use of that same
register ~26 slots early, identically across three structural variants; argument
pins are not local the way $s pins are.

With §368 and §373 these now form a usable four-way rule for when a pin helps,
when it fights the allocator, when it is ignored entirely, and when it acts at a
distance.
2026-08-31 22:26:02 -06:00
Drew T 5c317dbe5f docs: wire the S68 tools into SETUP.md (R21) and the playbook (when to use them)
A tool nobody knows about is invisible work. Audit found neighbor_ref (built an
hour ago), residual_rules, lane_inflight and r22_verify in NEITHER doc, and
wall_sweep in the playbook but not the inventory.

SETUP.md gains a tooling-inventory row for all five with what each is FOR.

wave-playbook gains §2b: run neighbor_ref for EVERY card, placed right after the
seed_ref step because it answers the weaker and far more common question ('which
matched function should this agent READ?') that seed_ref structurally cannot. It
carries the measurement that justifies it -- a ~20x token swing on that single
variable -- and the failure it prevents: func_8017BEBC's card said 'no banked twin'
while a matched 755-instruction near-twin sat 3,700 lines up IN ITS OWN FILE.

Also states the two honest limits: an opt-level mismatch is PENALISED not merely
ranked low (§116 -- an -O2 example misleads an -O0 target), and a neighbour is a
worked example to READ, never a body to copy (§168 law 1, cousin-remap 0/26).
2026-08-31 22:25:43 -06:00
Drew T ba394da75a docs: spec the TRIAGE LADDER for next session, with its 32 free banks listed
The companion to neighbor_ref.py (built). Written so a session with none of S68's
context can finish it: what it is, where it sits in the pipeline, that
tools/residual_rules_b.py is already ~70% of it with its held-out scores, the
asymmetric failure mode that makes the R39 acceptance test mandatory (a false
'skip - already banked' silently drops a bankable function), and the falsifiable
predictions.

Includes the immediate payoff, verified by me rather than taken on trust: 10 drafts
are byte-MATCHES once an extern derived from the target's own .s is added (10 of 10
confirmed with match_one, closeness 0, patched drafts at .run/rules_b/*/autodecl.c),
plus 22 more that already match standalone and were misfiled as failures.

Also records the experiment's most important number: two INDEPENDENT
implementations converged at ~1-2% on pure cookbook-shape rules, so that tier's
ceiling is the POPULATION (surgical residuals live at the end of escalations, not
in first-pass wave output) and it belongs in escalation loops, not wave triage.
2026-08-31 22:09:11 -06:00
Drew T 7392fcf7c3 docs: accelerators #15 (the differential-oracle harness) + the generic decomp package thesis
#15 — the tool worth building FIRST in any decomp, because it works at 0% and
compounds: run every question down TWO independent paths on a schedule and fail on
disagreement. Ten-plus S68 blockers had one shape — a tool computing a TRUE number
about a NARROWER world than we believed it covered — and EVERY one was caught by
two measurements disagreeing, never by review. R32/R34/R40 already say this and
were not enough: they are rules applied by whoever writes the tool, and in S68 I
wrote R34's warning into one docstring and rebuilt the exact defect it warns about
an hour later in another file.

Includes Drew's scheduling half, which this project only ever did by accident: the
widening is PERIODIC. Tooling is not wrong when written, it goes STALE as new
idioms reveal populations it cannot see. At every phase close ask 'which scanner's
denominator just got wider?' — that question converts new knowledge into free
banks. The §332 sweep is the worked example: one review, 10 fns / 1,027 ins
reclassified, one in-flight escalation stopped mid-spend.

generic-decomp-package.md — what a NEW decomp inherits on day one and does BEFORE
cracking: mine the COMPILER SOURCE and sibling projects for idioms (this project's
best late idioms came from reading gcc-2.7.2's own passes and needed no matched
function at all — week-1 work done in month N), port the families/twins/dedup/carve
layer first, then the oracle harness, and only then crack. With the honest caveat
that tooling-first makes the cheap half free and does NOT shrink the hard tail.
2026-08-31 22:06:20 -06:00
Drew T d8b7fb4e49 docs(playbook): §1b — the §332 walls are now ENUMERATED, wire the sweep into the draw
tools/wall_sweep.py --emit-exclude feeds draw_waves --exclude directly. 10
functions / 1,027 instructions over 1,378 open-stub .s files, against §332's
'6 fleet-wide' with two named.

Recorded what it caught immediately: main/func_8005D734 was already escalated to
Fable at closeness 8 when the sweep listed it, and its site is exactly the residual
that agent described -- stopped. Filtering the live queue dropped two more before
they were drafted (func_8005D9C4 133 ins, func_8005F450 159 ins).

The §188 epilogue half is still NOT built and is now named as such rather than left
implied: its detector exists inside oracle_reorder.py and has never been run as a
sweep.
2026-08-31 20:02:56 -06:00
Drew T 0e50fbc84f docs(playbook): §1b — the walls ledger is always incomplete, and each gap costs an agent run
A wall nobody has met yet is invisible to the draw filter, so new ones are found by
PAYING an agent to hit one. Twice in S68 on main: func_8005E228 (a full run, then
banked the §265 verbatim-asm way) and func_8005F0C8 (289k tokens to reach closeness
36 with the residual confirmed as §188's epilogue by oracle_reorder.py).

Neither is a model failure. An agent handed a wall returns a NEAR with an
unexplainable tail, which looks exactly like a hard function -- and an escalation
cannot beat the toolchain, so escalating one is guaranteed waste.

The fix is named rather than left as folklore: run the §188 epilogue-shape detector
over every open stub AT DRAW TIME. It already exists inside oracle_reorder.py and
has never been run as a sweep. Until then, treat 'NEAR with an epilogue-shaped
tail' as a walls candidate and check it with the oracle BEFORE escalating.
2026-08-31 19:54:36 -06:00
Drew T c42b3dbc35 docs(cookbook): §373 — the dead-reset cse-breaker, the anti-dep pin, and pri(asm)=1
From the fable escalation that closed ov_SC06_010/func_8017E764 (8 -> 0, BOTH
clusters), and it is three findings not one:

1. DEAD-RESET CSE-BREAKER. To stop cse merging two computations of the same
   expression WITHOUT an asm's scheduling footprint: name it, use it, then
   'p = 0;' immediately after. cse invalidates at the second set and flow deletes
   the dead set BEFORE sched1 -- zero bytes, zero LUID disturbance. An empty-asm
   re-tie by contrast is a REAL pre-call insn whose def->asm->arg chain fronts that
   argument's addiu, and on this function that WAS the second residual cluster
   (§361 confirmed: the lever caused the bug it was later blamed on). Removing the
   dead-reset costs +2 ins / +8 frame bytes, so it is load-bearing.

2. A REGISTER PIN THAT DELETES A sched2 ANTI-DEP. sched1's birthing boost sinks a
   single-set 'la' to its consumer, local-alloc reuses the freed scratch, and
   sched2 is then walled by store-reads-$v0 -> la-writes-$v0. A pin on the address
   pointer deletes the anti-dep. Note this is where a pin is RIGHT, against §368
   where pins measured worse -- the discriminator is breaking a false
   anti-dependence (works) vs out-arguing local-alloc about an allocation (fails).

3. HARD FACT: gcc-2.7.2 insn_cost (sched.c:1363) sets LINK_COST_FREE on any dep
   whose consumer is unrecognizable (INSN_CODE<0 = every inline asm), so
   pri(asm)=1 ALWAYS. An asm can never inherit a load's latency into its priority.
   That closes off a whole family of plausible levers.

Also cross-referenced §370: this run was briefed to test that bound FIRST and
reported it did NOT explain the residual. §370's claim is unchanged and still
narrow; the transferable habit is checking whether a recorded bound covers your
case before declaring a residual unreachable.
2026-08-31 19:20:46 -06:00
Drew T 672431e325 fix(r22+gater): R22 now REFUSES while drafters are live; §372 the copy-capture pair
tools/r22_verify.sh (NEW, promoted from .run so it survives the session):
'make clean' deletes asm/ AND build/, and THREE times this session that raced a
live lane -- a subagent authorised to splice src/800.c produced a FALSE
'212 passed, 1 failed' red, and two drafting agents reported their target's asm/
tree MISSING mid-draft (one survived only by finding an old snapshot). Drafting
agents never WRITE src/, which is exactly why 'check for a dirty tree' does not
catch them: they DEPEND on state this operation destroys. The guard refuses when
any wave scratch dir was touched in the last 6 minutes, names the live agents, and
offers R22_FORCE for a drained lane. R54 -- a guard that is not running is not a
guard, so this refuses instead of relying on me remembering.
Negative-controlled BOTH directions: refuses with 5 live agents named; passes on an
idle lane AND on a lane whose scratch is 30 minutes stale (no false positives).

fix(gater): the in-tree main commit message said '0 fn(s)' for a commit that
contained a real bank. corpus memoizes, so querying corpus.stubs immediately after
the bank returns the STALE pre-bank set. Derive the list from harvest_verify's own
verified-out file instead (R33: derive from the invariant the tool already wrote).

§372 ★★★ THE COPY-CAPTURE PAIR. Tell: a REGALLOC-PERM residual whose wrong-register
rows READ the destination of a nearby MATCHING copy insn. Two passes re-base uses
onto a copy's destination -- cse.c make_regs_eqv (canonical-reg rewrite of later
same-EBB uses) and local-alloc.c optimize_reg_copy_1 (forward-substitution when the
copy's src does not die in it) -- and BOTH die to one zero-byte edit: spell the copy
'P = X + zr' so SET_SRC is a PLUS, which is not a reg-reg copy and records no reg
equivalence, while emitting the byte-identical 'addu $rd,$rs,$zero'.
Notably the escalation was told to CHECK whether §368's tell applied rather than
assume it; it reported that it did NOT (pure shift/slti rows, no commutative
operands) and found the real cause from RTL dumps. That is §361's procedure working.
2026-08-31 18:51:21 -06:00
Drew T 54c0624e49 docs: §371 the module-binary -O0 carve route + the spimdisasm rodata trap; SETUP.md S68 tooling rows (R21)
§371 ★★ carving a SINGLE-OBJECT module binary. One 'unaddressable content'
message was THREE stacked causes (interior-YAML-comment symbol-list truncation, a
trailing verbatim-asm chunk with no region, bare tag forward decls) -- fix one and
the message does not change, which is why it read as an impassable wall.

Then the reusable part: spimdisasm migrates single-referenced rodata into a
function's .s ONLY within the same subseg, so a carve that moves the function
silently DROPS it, and INCLUDE_RODATA cannot bring it back (splat marks it migrated
segment-wide and emits nothing). Rename the .rodata subseg to the object its
emitters moved to; the regenerated .s coming back byte-identical is the proof.

Also recorded: the Makefile -O0 glob hunk is PART of the carve, not a follow-up;
interleave_check's DRIFT on md_MAIN_003 is PRE-EXISTING and must not be 'fixed';
the still-open second-carve refusal (UNOWNED rodata 0x800cedf8); and the §126 plan
for the remaining 8 -O0 stubs (three are ADJACENT so one region covers them).

SETUP.md (R21): three tooling-inventory rows covering gater_lane/escalate_fable/
o0_boundary, the six overlay-layout fixes, and the module-binary carve route.
2026-08-31 18:34:38 -06:00
Drew T 2a0808e3dc docs(cookbook): §370 — a HARD BOUND from sched.c, plus the reorg slot-steal diagnostic
The third fable escalation did NOT close its function (main/func_8001BC6C,
33 -> 28 over ~45 measured compiles), so the checkpoint's '2 for 2' is corrected
to 2 closed of 3. The failure is banked because a negative result that tells
future agents when to STOP is worth its tokens.

THE BOUND: sched.c schedule_select ALWAYS fronts a ready load over an
equal-priority ALU leaf (potential_hazard), so no C spelling can emit an ALU chain
before loads that are simultaneously-ready same-priority leaves. If a target shows
that order, look for reorg slot-steals, hard-reg dependency walls, or late in-block
consumers BEFORE burning compiles on statement permutations.

Also banked: the reorg fill_simple_delay_slots slot-steal diagnostic and its
split-tree precondition (the accumulator must live outside the $v0-heavy tail to
be eligible), three supporting levers, and three REFUTED ones with measurements --
a dead-init boost-kill is a no-op because cse delete_dead_from_cse removes it
before the final reg_scan, dense-block re-ties cost +4 to +9 because each re-tie
re-anchors its own load, and the -fno-schedule-insns oracle does not discriminate
when the residual is a multi-pass composition.

This run applied §361 CORRECTLY -- it removed the prior agent's pin first and
exonerated it for the head -- which is why its four-pass diagnosis can be trusted
where the previous single-tie claim could not.
2026-08-31 17:29:45 -06:00
Drew T 0816ea0576 chore: refresh the backlog + fleet digests after the S68 banks 2026-08-31 17:27:15 -06:00
Drew T 92e3ff9272 docs(cookbook): S68 harvest round 2 — §363-§369, including the reload-remat constant
§363 ★★ the OVERLAY-LAYOUT assumption is a systemic bug class and main is the
     exception that finds it — SIX measured instances, four in one session, each
     of which presented as 'the model wrote bad drafts'. Pass the fact you have
     (corpus.Stub.path/.asm_dir, the Makefile's <b>_OUT/<b>_CHECK_SHA/...); never
     reconstruct it. Two of the six were the SAME tool one call deeper with an
     IDENTICAL symptom, which is what makes a one-layer fix feel complete.
§364 ★ the libgpu P_TAG bitfield spelling is OPT-LEVEL DEPENDENT: required at -O0
     (store_fixed_bit_field fixes the or's operand order), byte-WRONG at -O2
     (MEM_IN_STRUCT_P lets the alias oracle CSE a load across the tag store,
     -4 ins/block). First case where the right answer flips with opt level.
§365 pin BOTH masks or neither (one pin measured 36/34, both -> MATCH)
§366 ★★ group_case_nodes merges STACKED consecutive case labels — give every case
     its own duplicated body and let cross_jump fold them back. The three stacked
     runs were EXACTLY the -25 length drift. First-try MATCH on 360 ins.
§367 reconciling a decl conflict between two drafts for the same TU: match the
     already-banked spelling and adapt the USE SITE; a block-scope shadow works
     for a typedef but NOT for an object.
§368 ★★★ the RELOAD-REMAT CONSTANT — a function-scope single-set local that
     global-alloc cannot color makes reload rematerialize the constant per use and
     choose the register by order_regs_for_reload, reaching registers no
     'register __asm__' pin can (pins measured WORSE). The tell is a
     wrong-register row whose COMMUTATIVE OPERANDS are also swapped.
§369 reuse the compare constant's own variable for a coalescing mask; and
     aggregates take their frame slot at BLOCK ENTRY while scalars take one only at
     &x, so an inner-block pad is a frame ORDERING dial (sharpens §333/§358).

Index: 1020 sections, 14 symptom buckets. Cookbook 383 -> 399.
2026-08-31 17:25:47 -06:00
Drew T c55cebea9b docs(cookbook): S68 harvest — §354-§362, nine sections from the wave and the whale carve
§354 the giv worth-while test as a dial (re-associate the addend into the index
     term; strength_reduce declines and $fp is freed) - ov_SC03_105/func_801824CC
§355 a remapped sibling's SOURCE bias is not its EMITTED bias; gcc re-anchors
     reduced givs, so do NOT hand-shift offsets to match the asm
§356 measure a draft in the TU it will live in: 39 of 43 'undeclared' cc1-fails
     were the standalone probe's environment, not the draft (R35)
§357 one struct pointer, not two - a second source variable builds a THIRD iv
§358 sharpens §333: an UNREFERENCED fixed-size aggregate local is load-bearing;
     expand_decl slots every aggregate, so an unused decl is a frame-layout knob
§359 spell a sign-widen as an explicit two-step function-scoped temp; a single
     (s16) cast and a register pin both measured FAILED
§360 the 'compiler found a shorter equivalent' pair - with its third lever marked
     REFUTED rather than deleted, so nobody re-derives it
§361 ★ a loop-tail byte signature that names its source shape, and the law that a
     'scheduling tie' may be an artifact of your own earlier lever. The prior
     agent's sched1 diagnosis was WRONG and its own hack was the cause.
     Escalation economics: sonnet 229k tokens no bank, fable 74k tokens MATCH.
§362 two traps when a carve moves a stub into the -O0 TU (rollout_o0 goes blind;
     the §8b decl layer conflicts with the shared header on 7 symbols)

Index regenerated: 1013 sections, 14 symptom buckets.
2026-08-31 16:37:35 -06:00
Drew T ed53a68f18 feat(p31 s68): deferred propagation done honestly (2 banked) + seed_ref was offering DEAD TEXT
The S67 FINAL-3 OPEN item, plus the two defects found while doing it.

* fix(dedup_propagate): the tool could not run AT ALL. S67's -j patch wrote
  `os.environ` at module level in the one module that imports `os as _os`, so
  every invocation died with NameError before doing any work. Propagation was
  not deferred, it was impossible. Import-checked the other 7 -j-patched tools.

* propagation, honestly scoped: the real closable set is 11, not 32, derived two
  independent ways that agree (seed_ref exact+same_addr, and a direct corpus
  derivation). The 3,161-entry --auto-from plan over 53 overlays is dedup
  hygiene over already-matched code and closes almost no open stub.
  Applied: 2 banked byte-green (ov_SC04_018 func_80181270, func_80182AF8);
  3 gate-refused and cleanly reverted; 6 blocked with named blockers
  (3 CARRY-FIXABLE, 3 func_80144B9C not-inline-def -> needs the o0 whale carve).
  R22 clean fleet: extract 212/212, check 213 passed 0 failed of 213, rc 0/0/0.
  Frontier 453 -> 451.

* fix(seed_ref): REFUSE targets in LINKED subsegs. The playbook calls this tool
  "the fleet-wide answer" and it reported 82 open stubs with a banked twin --
  43 of them main stubs whose TUs the linker script never references. Any C
  written there compiles, links and leaves the SHA1 green WHETHER OR NOT IT IS
  CORRECT, so a mechanical twin lane fed from that list could have minted up to
  43 gate-green FALSE matches the byte gate cannot see. draw_waves has refused
  these since S66; this oracle did not. The refusal is counted and printed, not
  silent. NC: guarded 39 subset of raw 82, all 43 dropped are main, the non-main
  population is identical.

* wave drawn: .run/S68o1 (24 opus 187-770 ins) + .run/S68m1 (30 main), cards +
  packs + wave_args asserted, queue of 53. Drafting opened at concurrency 5.
2026-08-31 15:59:01 -06:00
Drew T 93ea53217e docs(playbook): a carve writes THREE outputs — merge all three, splice overlays.mk per block, gate jtbl with --r22 2026-08-31 15:17:27 -06:00
Drew T 5bcb322283 docs: gating is fully parallel — no serial lane; jtbl unlocked via isolate_asm; launch detached with setsid 2026-08-31 14:55:39 -06:00
Drew T 3a4eac272e docs(cookbook): §353 -fno-thread-jumps as a pass-identification oracle; launder the value to keep a dead re-test 2026-08-31 14:37:16 -06:00