# Crack-wave performance metrics > **Evolvable reference (docs/ layer).** Started 2026-08-04 (Phase 30, sessions S33–S37). > **Append one row per wave.** The point of this file is that the wave harness has knobs — the > prompt, the concurrency shape, the model tier — and their effects are only visible if the numbers > are recorded in one place. Two of them were already measured to matter a lot (§ below). > > Sources, all derivable — do not hand-transcribe (R33): > - counts/tokens/duration: the Workflow completion notification (`agent_count`, `subagent_tokens`, `duration_ms`) > - per-agent wall-clock + parallelism: `min/max(timestamp)` per `agent-*.jsonl` under > `~/.claude/projects/.../subagents/workflows//` > - banked: the whole-binary gate log (`.run/s*_gate.log`) — **the gate is the arbiter, never the > agents' claim** (G3/P9) ## The table | wave | script | targets | templ ins | agents | tokens | wall | parallelism | median / slowest agent | claimed | **banked** | +members | |---|---|---|---|---|---|---|---|---|---|---|---| | 1 (S33) | `s33w.js` | 17 | 26,227 | 25 | 6.87M | 169 min | 4.8× | 33 / 63 min | 15/17 | **15** (13+2 rec) | 65 | | 2 (S34) | `s34w.js` | 13 | 37,943 | 19 | 4.51M | 208 min | 2.7× | 20 / 79 min | 11/13 | **10** (9+1 rec) | 18 | | 3 (S35) | `s35w.js` | 13 | 17,644 | 14 | 2.73M | 140 min | 2.1× | 9 / 51 min | 13/13 | **13** (12+1 rec) | 21 | | 4 (S36) | `s36w.js` | 14 | 16,844 | 17 | 2.99M | 136 min | 2.5× | 14 / 48 min | 14/14 | **14** (13+1 rec) | 26 | | 5 (S37) | `s37w.js` | 16 | 16,884 | 19 | 2.71M | **82 min** | **3.8×** | 9 / 50 min | 16/16 | **16** (16+0 rec) | 26 | | 6 (S38) | `w6.js` | 16 | **50,596** | 24 | 5.20M | 71 min | **7.4×** | 25 / 40 min | 14/16 | **7** | 25 | All waves: Sonnet drafters with an Opus escalation rung (§136i), whole-binary byte-gate as the sole arbiter, R22 clean-fleet 140/140 after every banked batch. ## Finding 1 — the PROMPT is the lever, and the agents write it Bank rate **76% → 77% → 100% → 100% → 100%**, with the models and the gate held constant. The only variable was the prompt's `extra` block. The jump came from **STEP 0: `grep -rn "" src/`** using a distinctive literal from the target `.s`, placed *ahead* of `engine_core.h` in §136c's search order — because §136c's first two steps are same-TU/shared-header scoped and structurally cannot reach a banked twin in a *different overlay's* TU, which is where the big template classes live. **That step came from a wave-2 agent's `index_gap` report.** The wave schema asks every agent for `index_hit` / `index_gap`; harvesting those into the next wave's prompt is what compounds. By wave 4 most agents cited step 0 by name and reported `index_gap: none`. *Honesty caveat:* wave 3–5 targets also trended easier (smaller families, more banked twins available), so the prompt is not solely responsible for 100%. The claim that holds without qualification is the direction and the mechanism, not the exact percentage. ## Finding 2 — `pipeline()` vs batched `parallel()`: 40% faster on 14% more targets Waves 1–4 split each wave into two `parallel()` batches, which is a **hard barrier** — batch 2 cannot start until batch 1's slowest agent finishes. Visible directly in the launch timestamps as 37–50 minute dead gaps at each boundary. | | wave 4 `parallel()` | wave 5 `pipeline()` | |---|---|---| | targets | 14 | **16** | | wall-clock | 136 min | **82 min** | | parallelism | 2.5× | **3.8×** | | median agent | 14 min | 9 min | The batching existed to dodge S10's 30-wide server throttle, but the harness already caps workflow agents at `min(16, cores-2)` and these waves are 13–16 targets — so it bought nothing and cost a barrier. **Use `.run/s37w.js`'s execution block for every future wave.** **The remaining floor is real:** the slowest single agent is still ~50 min at 200–300 turns. That is genuine `match_one` iteration (one agent tested 470+ statement orderings on a 793-instruction function). Wall-clock cannot go below the slowest chain, so the lever there is target *selection*, not concurrency. ## Finding 3 — economics Roughly 170k–300k tokens per banked head across waves 3–5 (the stable regime). But a head is not the unit of value: **the unit is the head plus its propagated members**, and the sweep rate is a property of the FAMILY, not the wave — wave 3 swept 21/21 while wave 2 swept 18/165, because wave 2's big families are per-location variants that do not template (settled by probe: remapped member is BUILD OK **and** byte-different ⇒ genuine per-member codegen). **Rank targets by open templatable instructions derived from `corpus.stubs`, and expect the sweep yield to be bimodal, not average.** ## Finding 4 — a perfect gate is a signal that the prompt rules landed Wave 5 is the first **16/16 banked with ZERO reconcile**. Waves 1–4 each needed 1–2 declaration reconciles after the gate; wave 5 needed none. The difference is that by then the prompt carried both §138 rules (the *(macro-shape, TU-shape)* pair, and the reconcile-direction line-number check) plus the wave-4 lesson that two targets sharing a TU can create each other's conflicts. **The reconcile lane is the fallback, not the plan — when it goes quiet, the prompt is doing its job.** Lifetime reconcile record across the session: **21/22**. ## How to add a row After a wave's gate + sweep land, before the commit: ``` # tokens / agents / duration: from the Workflow completion notification # parallelism + per-agent spread: python3 - <<'PY' import json, glob, datetime d = "" T = lambda s: datetime.datetime.fromisoformat(s.replace("Z","+00:00")) ag=[] for f in glob.glob(f"{d}/agent-*.jsonl"): ts=[T(r["timestamp"]) for r in map(json.loads, open(f)) if r.get("timestamp")] if ts: ag.append(((max(ts)-min(ts)).total_seconds()/60, min(ts), max(ts))) wall=(max(a[2] for a in ag)-min(a[1] for a in ag)).total_seconds()/60 tot=sum(a[0] for a in ag); ag.sort() print(f"{len(ag)} agents · wall {wall:.0f}m · agent-time {tot:.0f}m · {tot/wall:.1f}x · " f"median {ag[len(ag)//2][0]:.0f}m · slowest {ag[-1][0]:.0f}m") PY ``` Related: cookbook **§138** (the reconcile/search rules these waves produced), memory `wave-prompt-seed-step0-and-gaps` (what to seed the next prompt with), `docs/effort-map.md` (Ultracode/breadth policy), `docs/calibration.md` (templatability measurements). ## Finding 5 — rank waves by INSTRUCTIONS BANKED, not heads; and the knob that moved in wave 6 Wave 6 deliberately changed the difficulty knob: **50,596 templatable instructions offered vs ~16,800**, median target **438 instructions vs 143**, max **947 vs 397**, and most targets in the `has_mid_jr` (jump-table-carve) class. Its bank rate — **7/16 heads** — therefore is **not comparable** to waves 3–5's 100%, and should never be read next to them as if the knob were fixed. **By instructions, the bigger pool won:** | | wave 5 | wave 6 | |---|---|---| | pool offered | 16,884 | **50,596** | | heads banked | 16/16 | 7/16 | | ins in banked heads | 2,753 | 2,204 | | propagated members | 26 | 25 | | **total instructions banked** | ~7,200 *(est.)* | **10,616** *(exact)* | | pool realised | ~43% *(est.)* | **21%** | Wave 6's 10,616 is **exact** — `make report` moved 12,368,236 → 12,378,852, matching the hand-derivation to the instruction. Wave 5's figure is an estimate (its per-family member breakdown wasn't recorded — *record it from now on*). So wave 6 banked **~45% more instructions 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-instruction head, became **4,485 instructions across 15 siblings** for ~0 agent tokens. **Head count flatters small-target waves; instruction weight is what moves the fleet.** **The metric to beat is POOL REALISATION (21%), not bank rate.** A wave banking 16/16 of a 17k pool is worth less than one banking 7/16 of a 50k pool. And wave 6's 21% is a floor, not a ceiling: it lost an entire gate cycle to the `_reload_corpus` defect (§139), and 9 of its 16 targets are still open and routable rather than refuted. ## Finding 6 — a wave's tally is a COVERAGE claim, and needs its own assertion Wave 6's first gate printed `BANKED 5 / FAILED 1` over **16** drafts. Ten produced no verdict at all because the child crashed and the driver only grepped stdout for two line-prefixes. Nine of the ten were claiming MATCH, and one of them (`func_8017EA84`, 579 ins) banks **byte-identical** under the fixed path — a real match reported as nothing. **Any row in this table is a coverage claim.** Before recording one, confirm the gate accounted for every draft (`banked + failed + no-verdict == drafts`, now asserted in `.run/s6f_gate.py`). Full post-mortem: cookbook **§139**. --- ## Wave S40-1 (2026-08-05) — 8 targets, the first wave ever aimed at the open-only h_norm clusters **Pool verified BEFORE the wave (R14).** The frontier report's cluster pool was carried with an explicit "not verified" caveat, and its *other* headline claim (the whale open in 4 SC07 overlays) had already proved 3/4 wrong. Measured from the sigs instead: | | clusters | fns | ins | multiplier | |---|---:|---:|---:|---:| | claimed | 1,689 | 5,956 | 326,261 | 2.7× | | **measured** | **1,677** | **5,795** | **319,755** | **3.68×** | Within 2–4% on size, and the multiplier is **better** than claimed. Verify each claim separately: the same document was right here and wrong about the whale. **Result — and the two numbers say different things.** | stage | result | |---|---| | `match_one` close=0 | **8 / 8** | | whole-binary gate, first pass | **5 / 8** | | after deterministic recovery | **8 / 8** — ~0 agent tokens | **All three first-pass failures were integration plumbing, each a different known lever, ZERO codegen walls:** | fn | gate error | lever | |---|---|---| | `func_801802EC` | `redefinition of morph_lerp` | strip the **§77 probe layer** — the draft carried types + a `static inline` helper so `match_one` could compile standalone; the real TU already defines them. Scaffolding is not part of the bank. | | `func_8018B238` | `conflicting types for D_80115158` | `recover_giant` — the draft declared it file-scope as a struct array while the TU declares `u8[]` **block-scope** inside other functions; block-scoping the draft's externs removes the collision. | | `func_8017EF54` | `conflicting types for func_8017EF54` | **§37/§124 def-side asm-label alias** — TU declares `void f(void)` for no-arg callers, byte-true def takes `s32` in `$a0`; no-prototype escape illegal once a param promotes, so the definition takes a private C identifier + `__asm__("func_8017EF54")`. | **The lesson for reading any future wave row: the gate number is not the close-rate.** 5/8 measured integration, not matching. Run the recovery ladder before recording a wave's yield, or the table will under-report the drafters and send the next wave hunting compiler walls that are not there. **Cost:** 1.31M subagent tokens, 8 agents, 0 errors. **Idioms harvested:** cookbook §144 (literal spelling picks the immediate encoding). **Defect found:** `.run/ghidra_c/func_8017EF54.c` is a stale decompile of the WRONG function — the prefetch cache is not trustworthy per-entry.