Commit Graph

15 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 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 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 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 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 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 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 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 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 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 022d50325a docs(playbook): the pgrep bracket is NOT enough when launch and wait share a shell
Measured a SECOND time in S67, and the first fix was incomplete. A waiter using the bracketed
pattern still matched itself and spun 1h35m, because the same shell command had LAUNCHED the job —
so its own command line carried the unbracketed 'gate_stage.py --binary ov_SC07_007' from the nohup
half. The regex gate_[s]tage.py does not match the literal bracketed text, but it happily matches
the plain text sitting earlier on the same line.

Rule is now: launch and wait in SEPARATE shell invocations, or better, wait on a completion MARKER
the job writes to its own log rather than on process liveness.
2026-08-31 13:51:48 -06:00
Drew T 00812fc62f docs(p31 s67): wave-playbook (the CURRENT pipeline) + seed_ref fix + harvest §333-§338
THE DOC GAP, and it cost tokens this session. `docs/automation-runbook.md` was titled "the
autonomous campaign, as it actually runs" while documenting the RETIRED OpenRouter/ox-alpha system
whose lanes are all deliberately DEAD. The current Claude-wave pipeline existed only as two dense
tooling-inventory rows in SETUP.md — reference, not procedure. Three of this session's costliest
mistakes were procedural and a playbook prevents each:
  * hand-typed a refill target -> invented func_80184F60 (2nd instruction of a matched function), 58k
  * hand-rolled a serial gate loop when parallel_gate existed -> ~1h for what took 103s
  * re-derived a function banked verbatim in ~20 overlays -> 102k

NEW docs/wave-playbook.md — start to finish, each guard paired with the MEASUREMENT that produced it
(that pairing is the part a generic decomp guide cannot have, and the seed of the future template).
automation-runbook.md retitled HISTORICAL with a pointer; SETUP.md §6.9 links the playbook.

NEW tools/seed_ref.py — the cross-TU banked twin, joined on corpus signature hashes (no atlas knn,
~2s fleet-wide), wired into t5_cards.py. FLEET: 87 open stubs have a banked twin; 41 of them sit in
twin_sweep's refusal ledger, invisible to BOTH tools at once. Documents twin_sweep's two holes:
load_sigs covers 141/213 binaries (main, resident, all md_MAIN_* absent), and one curated symbol
name silently disables an entire binary via a bare `except Exception: pass`.
Schema note: seed_ref's binary/fn are the EXEMPLAR's, because api_agent greps src/{binary} for {fn};
naming them after the target would send every agent grepping for itself — caught pre-ship.

HARVEST §333-§338 from the s67o2_1/pool_1 waves:
 §333 frame size is set by DECLARED aggregates, not used ones — an unreferenced trailing local is a
      dial (3 instances; one worth 30 of 32 residual rows)
 §334 a reload spill slot rounds to BIGGEST_ALIGNMENT for align AND size: one 4-byte pseudo grew a
      frame by 16 (82->53)
 §335 `extern u16 A[]` at a variable subscript allocates ~8B/access of dead stack temps that inflate
      the frame with ZERO extra instructions — invisible in a body diff (141->20)
 §336 the §5a barrier goes at the BOTTOM of the twin; find_cross_jump walks BACKWARD
 §337 the CC1-ONLY blocker class: blocker_probe's static oracle says "none" and cc1 still fails
 §338 _sltiu_bounds misreads a non-switch sltiu as a bounds check, over-spanning the table

gate_wave.py now STREAMS both lanes (R55) — it captured output and printed at the end, leaving a
zero-byte log indistinguishable from a hang.
2026-08-31 13:48:56 -06:00