A pack carrying a previous attempt said only 'the gate did not accept it, so it is wrong somewhere'.
That discards the one datum that decides how the agent spends its budget. Now the builder runs
match_one on that draft and embeds the verdict:
* near -> the closeness, the verdict sig, and the residual rows (idx / mine / tgt, capped at 16
with an honest '... N more'), plus how to READ them: two adjacent rows with the same
instructions in the opposite order = a SCHEDULE swap; a register-only difference = the
value came from the wrong place (often the copy, not the pre-copy value); a beqz/bnez
row = invert the test and swap the arms, constants included.
* match -> NOT a drafting job. The body is byte-correct in isolation and the gate refused it for an
INTEGRATION reason, so the pack names the $0 recover_integration --probe-only instead of
letting an agent burn a wave slot redrafting a correct body. If the probe also says
MATCH the residual is outside the function (the section-8e JTBL_PADS class).
Measured on the two t5u seeds, which I injected BY HAND this session before automating it:
func_8017F234 = 3 mismatched of 202 (a schedule swap + an "andi" reading the copy instead of the
pre-copy value); func_8017E7E8 = 11 of 66 (inverted branch + a cast written back into the variable
instead of a temp). Told that, an agent edits one use site; told "wrong somewhere", it re-derives 202
instructions.
Cost: one compile per target that HAS a prior draft; --no-residual opts out. Failures are swallowed
into a "(residual not measured: ...)" line — measuring must never break pack generation.
Control: rebuilt t5u's 15 packs into a scratch dir — both seeds gained the block automatically with
the same numbers I measured by hand, and a target with no prior draft is byte-identical to before.
The t5s/t5t distill returned three 'new lever' claims and the verifier REFUTED two as rediscoveries:
* func_8017E044's zero-byte __asm__ against reorg's delay-slot steal IS §5a/§34 (+§164-33/§164-36),
already indexed at cookbook-index.md:22;
* func_8017C014's ternary-vs-if-chain LICM effect is the loop.c movable gate (REG_N_SETS==1)
already documented for a recomputed CONSTANT — here firing on a computed loop-invariant EXPR.
Only func_8017EB30's survived, as an ADDENDUM to §165-03 — and the verifier proved it by reading the
target .s itself: the same 279-ins template, same //, as §165-03's byte-proven sibling
func_8017F2D4 in the adjacent overlay. Filed with its UNPROVEN label intact (that draft did not pass
the whole-binary gate — R14/G3).
THE REAL FINDING is the rediscovery rate, so §5a gains a FINDABILITY addendum: the law was there and
the agent could not find it, because the index states the symptom as 'gcc stole an instruction into a
branch delay slot that the target leaves as nop' and what the agent actually SAW was LENGTH-DRIFT/1
at closeness 45, an extra j absent from the target, and a DUPLICATED store — the nop never appeared
in its diff at all. The addendum indexes those three alternate tells. Same shape as S64's §41
addendum: the knowledge base's gap is retrieval, not content.
Index 921 sections, green.
First wave at the new 1x15 cap (5x plan). Bank rate 13/15 = 87%, against t5s's 24/29 = 83% — halving
the wave did not cost quality. Banked: func_800CAE0C func_800CB028 func_8017C120 func_8017CD9C
func_8017E0FC func_8017EADC func_8017EB34 func_8017EC78 func_80182AFC func_80182C78 func_8018A124
func_8018B698 func_8018B8B0.
Misses: func_801831B4 (71 ins, closeness 10 — a D_801B7A84 reload-scheduling residual the agent
probed 5 structurally distinct ways, byte-identical residual each time) and ov_SC03_023:func_8017BEBC
(246 ins, closeness 45) whose ov_SC03_012 sibling was hand-banked earlier this session — try a family
remap there before spending another wave slot.
R22: verified from a CLEAN rebuild after the ov_MAIN_012 repair (commit:3195).
Three properties compose into tree corruption under concurrency:
(a) assert_write_set measures a GLOBAL git status, so a concurrent run's writes read as THIS
run's blast-radius violation and abort it;
(b) an abort does NOT restore the stage edits already on disk;
(c) gate_stage's commit is a deliberately broad 'git add -u src/' — and it must be, since
propagation touches many overlays and a narrower filename glob once DROPPED four R22-verified
banks — so a concurrent --commit sweeps the aborted run's half-applied edits into its commit.
Measured today: xargs -P 4 over 33 binaries put 696 broken lines of ov_MAIN_012 into md_MAIN_026's
+1 bank commit; check-all went 212/213 and the wave bank was blocked behind it (R59).
Narrowing the gate's git add was the WRONG fix (it would restore defect (c)'s predecessor). Instead
the driver enforces its own contract: flock on .run/recover/.driver.lock, refuse loudly (R43).
Control: with the lock held -> rc 1 REFUSED; lock free -> rc 0 and the probe runs normally.
CAUSE — a gate's commit is a broad 'git add src/', so it is NOT safe under concurrency (R59: a
gate commits only its OWN block). I ran the stranded-draft sweep with xargs -P 4; the blast-radius
guard correctly ABORTED several runs, but abort does not restore the stage edits already on disk,
and a CONCURRENT run's --commit (md_MAIN_026's +1 bank) then swept four other binaries' half-applied
demacroize/tu-scope edits into its commit — 696 lines into ov_MAIN_012, leaving it unbuildable
('parse error before D_80078E50', 'conflicting types for D_80126B58'). check-all went 212/213.
Restored the 4 contaminated files to commit:3193^ content. md_MAIN_026's actual bank is untouched.
Verified: all 5 binaries now build BYTE-IDENTICAL. No banked function was lost — stub counts prove
none of the 4 files carried one (a bank REMOVES a stub).
The recovery driver is NOT parallel-safe: assert_write_set measures a GLOBAL git status, so
concurrent runs see each other's writes. Run it serially until the commit is path-scoped.
Two defects in one filter, both measured on the t5s wave (24 banked / 29 transcripts):
1. FALSE POSITIVE. The keyword 'no cookbook lever' matched "MATCH on first compile, no cookbook
lever needed" — a note reporting a TRIVIAL function — and that was the ONLY selection out of 24,
while three genuine multi-lever notes went unpicked. A selector whose single hit is the one note
saying 'nothing to learn here' is inverted, not merely noisy. Keyword removed, NOT_NOVEL guard
added, and the phrasings agents actually use ('cookbook lacks', 'new lever', 'worth banking',
'levers not in') added. Same 24-transcript scope now selects func_8017E044 instead.
2. STRUCTURAL BLINDNESS. The distiller only ever considered BANKED functions — but the richest
idiom notes come from the HARDEST functions, which are the least likely to bank. func_8017EB30
(279 ins, four levers written up) and func_8017C014 (246 ins, two) both say 'NOT in the cookbook
and worth banking' and were never candidates. That defeats cookbook §52 — a model that FAILS to
crack a wall still distills the idiom that cracks its siblings — using the flywheel's own tool.
New --with-unbanked includes them, each carrying banked=False so the distilling agent knows the
lever is UNPROVEN by the byte gate (R14/G3).
R39 control: the previously-selected note is no longer selected (it was the false positive) and
nothing legitimately selected was dropped.
os.execv'd tools/blocker_probe.py with --drafts <run_dir>/drafts while that directory was still
created further down, so every non---draft-dir probe died with FileNotFoundError. Only --draft-dir
worked, because stage_drafts() had already populated the dir. Staging now happens first.
Control: the --draft-dir path returns the same verdict as before the move (ov_SC06_029
func_80185214 -> DIFF 52/52 ins, identical to the pre-edit run). --funcs now works: 10 backlog
candidates classified in one pass (2 real-TU MATCH, 3 conflicting-types, 2 too-few-arguments,
1 parse error).
Worth recording (R40): my own probe loop grepped for result rows and swallowed the traceback, so the
crash read as 'no blockers found' — a silently narrowed scope in the harness, not the tool.
mask_for(reloc_kind='26') returned 0, i.e. 'compare NOTHING at this position'. Both comparers pick
the mask from ONE side (diff_object_s from mine, diff_object_object from the target's), so a j/jal
there masked the OTHER side's instruction entirely. Reproduced on synthetic pairs of real encodings:
my 'j 8017e248' (0805f892) vs target 'bne v0,v1' (14430002) -> 0; vs 'nop' (00000000) -> 0; my 'jal'
vs target 'bne' -> 0; while the mirror (my 'bne' vs target 'j') -> 1. That asymmetry is the bug.
_j_mismatch cannot cover it: it fires only when BOTH sides carry an internal-j target, which a
j-vs-bne pair by definition does not.
Fix: return 0xFC000000 — the 26-bit target field stays masked (it IS link-time), the opcode never
is. diff_object_object's masked-slot test updated to match so the reloc symbol+addend check still
fires there.
R39 negative control (tools/stub_invariant_audit.py, the INCLUDE_ASM invariant): 2554 stubs, nonzero
3 before and 3 after — the same three known main length-delta survivors, same values. Zero new false
positives, over a population that exercises the changed path (812 stubs carry internal-j .text
relocs, 3164 such instructions).
Found by a t5s drafting agent on func_8017EB30 (reported as a one-sided internal-j check); verified
here to be broader than reported. No bank was ever at risk — the whole-binary gate is independent
(G3) — but every crack agent and the permuter scorer read this number. R35/R14.
recover_integration's macro-externs stage rewrote a draft's callee extern to the FLEET macro's
signature and then gated only the rewrite. func_ADDR names are per-address, not per-function, so
another overlay's 'extern void func_8017C338(void)' replaced this overlay's correct 4-arg decl and
manufactured the CC1-FAIL it reported as the draft's failure. The untouched draft banks
byte-identical (ov_SC03_012:func_8017BEBC, 246 ins, banked in the previous commit).
reconcile_and_gate(draft_rewrite=) now gates raw (pass 1a) then rewrites only what raw refused
(pass 1b), records the winning variant per fn, and re-gates that variant in pass 2.
harvest_verify.classify_fail kept the 'note:' half of a benign warning pair and labelled a built
draft CC1-FAIL with it; notes now drop with their warnings. Negative-controlled over 5 diagnostic
shapes — only warning+note-only changed (to the honest no-diagnostic label). R39/R57/R32.
Cookbook 920 -> 921 sections, index green.