playbook §2b has called neighbor_ref the biggest measured cost lever in the
wave since S68 (~20x token swing) and documented it as a MANUAL per-card
command wired into nothing — so it ran for approximately zero cards. Packs now
carry an ALREADY-MATCHED NEIGHBOURS block, same additive never-fail contract as
the past-attempt notes. First run: 30/30 targets had a matched neighbour.
It also shipped with a defect that would have silently un-done it:
neighbor_ref reports the SYMBOL-TABLE name, and for an unnamed function that is
Ghidra's FUN_8003a0e4 — which appears nowhere in src/*.c, where the function is
func_8003A0E4. An agent sent to read FUN_8003a0e4 finds nothing and concludes
there is no neighbour. _src_name resolves against the destination TU's own text,
falls back to the address, and shows the symbol-table spelling in parentheses.
Measured: 150 of 150 neighbour names needed resolving; 0 primary names remain
Ghidra-style. Checked against known-true cases first (resolves FUN_8003a0e4,
leaves func_8003A0E4 alone, leaves an unknown name untouched).
R61(b): the pack was asserting a name true of the symbol table and false of the
world the agent works in.
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.
Round-3 harvest measured a RETRIEVAL defect, not a knowledge gap: func_800CDBA8 and func_800CB00C
both re-derived laws the book already states (§165-19/§162d1/§30#3 birthing-boost; the
§135-1/§165-28 unsigned-switch-selector rule) by grinding match_one, with an EMPTY
cookbook_refs_used — they never grepped the index. SYS.md already tells them to ('START AT
docs/cookbook-index.md — it is symptom-keyed'); the instruction is there and gets skipped.
So stop asking. When the pack has ALREADY MEASURED the prior draft's residual and therefore knows
its klass, paste the matching symptom bucket from docs/cookbook-index.md straight into the pack,
capped at 40 rows with a pointer to the rest. Retrieval becomes push, not pull.
Mapping is klass -> bucket (REGALLOC-PERM/LOCAL -> register allocation & pins; SCHEDULE-REORDER,
OPCODE-MIXED, LENGTH-DRIFT -> instruction scheduling; DELAY-SLOT/BRANCH-POLARITY -> delay slots &
branches; WIDTH/IMM-VALUE/IMM-OFFSET -> types, signedness & width; ADDRESSING -> CSE; CC1-FAIL ->
declarations). An unmapped klass yields no bucket rather than a wrong one.
Negative control on the O21 slate, both directions: 12 packs carry a measured residual, 10 of those
get a bucket (2 have an unmapped klass and correctly get none); packs with no residual get none.
The loop closes visibly — the func_8017EDE8 pack now carries this round's OWN addendum about
§137's barrier failing in a cross-jump shared tail, which is exactly that function's residual class.
- match_one.py: a CPP/CC1/MASPSX/AS failure printed bare text and exited 1 even under --json, so
every programmatic caller got json.loads of a non-JSON line. claude_wave_packs swallowed 4 of 19
prior drafts as 'residual not measured: Expecting value' — the most actionable datum a pack can
carry (the draft does not COMPILE, here is the error) was the one it dropped. Negative control:
a near draft still measures identically (closeness 2, same residual rows); human mode unchanged.
- claude_wave_packs.py: renders that verdict, pointing the agent at the card's decl_prior block.
Coverage on wave r1 went 15/19 -> 19/19 packs carrying a measured verdict.
- wave_args.py (new): emits the claude_wave_draft.js args from <wave>/targets.json, asserting the
.s exists, that sub is exactly its parent dir, and that the pack exists. Written because I
hand-typed sub as 'ov_SC03_112/jr_80181D08' when the truth is
'asm/ov_SC03_112/nonmatchings/ov_SC03_112_jr_801817E0' (a stub's asm dir is named for its jr-carve
block, not itself) — all 19 agent oracles would have failed identically and read as a model
failure. Negative control: that exact string is REFUSED.
- draw_waves.py (new): draws waves off corpus.stubs cheapest-first, ledger-filtered, with
name-collision deferral (packs are name-keyed and refuse a duplicate). Re-measured the frontier:
the S65 tier map's '~557 cheap singletons (3-17 ins)' conflated one-member FAMILIES with small
functions — only 28 undrawn non-main stubs are <=17 ins; the bulk is 51-120 (258) and >120 (245).
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.