feat(phase-31): wave C banked 32 (R22 213/213) + tools/build_wave.py; 3 instrument defects fixed

- wave C: 35 cards (11 tell + 24 weak) -> 35/35 standalone (re-verified independently, R14)
  -> 32 banked / 3 near, 91% gate, 0 symbol failures (Law 4 prevention worked)
- weak lane proven for the first time: 24/24 on haiku; 890 candidates remain
- reach measured: 32 exemplars, 8 with sharers, x2 each => ~1.25x effective (the x134
  era ended in P25/29/30) -> throughput, not leverage, is now the lever
- tools/build_wave.py (pool=adapt|weak, corpus-derived open-stub filter, R35 gate guard)
- 3 self-inflicted instrument defects found+fixed+NC'd (P9, recorded not buried):
  pgrep self-match via shell=True; corpus.stubs() is addr->Stub not names (nearly
  declared both card pools spent); a wave fired on hand-typed placeholder cards (stopped)
- STRATEGIC: card lanes are ~0.23% of open ins/wave; the Atlas's head-crack bucket is
  1,276 groups / 186k ins with high-reach groups up to 265 instances -> retarget waves
  at atlas groups next
This commit is contained in:
Drew T
2026-08-14 23:44:03 -06:00
parent 238fdc53fd
commit 540d2cefaa
5 changed files with 866 additions and 761 deletions
+3
View File
@@ -1718,3 +1718,6 @@
{"ts": "2026-08-14 22:48:38", "addr": "0x80181724", "name": "func_80181724", "reach": null, "klass": null, "nins": null, "status": "near", "closeness": 11, "where_stuck": "residual: 11 mismatch", "best_draft": ".run/backlog_drafts/func_80181724.c", "binary": "ov_SC01_009", "source": "worker", "residual": [[1, "afbf0010 sw\tra,16(sp)", "00042400 sll $a0, $a0, 16"], [2, "3c010000 lui\tat,0x0", "00042403 sra $a0, $a0, 16"], [3, "00240821 addu\tat,at,a0", "afbf0010 sw $ra, 0x10($sp)"], [4, "90240000 lbu\ta0,0(at)", "3c018018 lui $at, %hi(D_80183A40)"], [6, "30a500ff andi\ta1,a1,0xff", "90243a40 lbu $a0, %lo(D_80183A40)($at)"], [7, "8fbf0010 lw\tra,16(sp)", "0c00a468 jal func_800291A0"], [8, "27bd0018 addiu\tsp,sp,24", "30a500ff andi $a1, $a1, 0xFF"], [9, "03e00008 jr\tra", "8fbf0010 lw $ra, 0x10($sp)"], [10, "00000000 nop", "27bd0018 addiu $sp, $sp, 0x18"], [11, "--", "03e00008 jr $ra"], [12, "--", "00000000 nop"]], "passes_tried": null}
{"ts": "2026-08-14 22:52:01", "addr": "0x8017daec", "name": "func_8017DAEC", "reach": null, "klass": "regalloc-order", "nins": null, "status": "near", "closeness": 19, "where_stuck": "v0/v1 register-ROLE swap in unk28/unk48/unk2A/unk4C cluster; count-exact 113=113 after the cse_expr \u00a72 hoist-vs-remat fix (nested-block ptr local + output-only asm kill). Prime permuter seed.", "best_draft": ".run/wave_p31c/ov_SC01_077/func_8017DAEC.c", "binary": "ov_SC01_077", "source": "p31-waveC-tell", "residual": null, "passes_tried": null}
{"ts": "2026-08-14 22:52:09", "addr": "0x80186078", "name": "func_80186078", "reach": null, "klass": "schedule", "nins": null, "status": "near", "closeness": 136, "where_stuck": "175 vs 174 ins; sp10/sp18 block fixed (target 15-22 exact); residual = gcc-2.7.2 scheduling cascade in unk90/unk44/unk48/unk4C cluster. Permuter length-profile fuel.", "best_draft": ".run/wave_p31c/ov_SC01_077/func_80186078.c", "binary": "ov_SC01_077", "source": "p31-waveC-tell", "residual": null, "passes_tried": null}
{"ts": "2026-08-14 23:12:40", "addr": "0x80189680", "name": "func_80189680", "reach": null, "klass": null, "nins": null, "status": "near", "closeness": 0, "where_stuck": "match_one MATCH but the whole-binary gate rejected \u2014 CAUSE NOT DETERMINED. FIRST re-derive the destination TU from the asm subdir: asm/<ov>/nonmatchings/<TU_stem>/<fn>.s => src/<ov>/<TU_stem>.c (the third path component IS the TU). Only then look for a decl conflict or a codegen residual.", "best_draft": ".run/backlog_drafts/func_80189680.c", "binary": "ov_SC03_014", "source": "worker", "residual": null, "passes_tried": null}
{"ts": "2026-08-14 23:23:38", "addr": "0x80181270", "name": "func_80181270", "reach": null, "klass": null, "nins": null, "status": "near", "closeness": 0, "where_stuck": "match_one MATCH but the whole-binary gate rejected \u2014 CAUSE NOT DETERMINED. FIRST re-derive the destination TU from the asm subdir: asm/<ov>/nonmatchings/<TU_stem>/<fn>.s => src/<ov>/<TU_stem>.c (the third path component IS the TU). Only then look for a decl conflict or a codegen residual.", "best_draft": ".run/backlog_drafts/func_80181270.c", "binary": "ov_SC04_018", "source": "worker", "residual": null, "passes_tried": null}
{"ts": "2026-08-14 23:27:45", "addr": "0x801802bc", "name": "func_801802BC", "reach": null, "klass": null, "nins": null, "status": "near", "closeness": 0, "where_stuck": "match_one MATCH but the whole-binary gate rejected \u2014 CAUSE NOT DETERMINED. FIRST re-derive the destination TU from the asm subdir: asm/<ov>/nonmatchings/<TU_stem>/<fn>.s => src/<ov>/<TU_stem>.c (the third path component IS the TU). Only then look for a decl conflict or a codegen residual.", "best_draft": ".run/backlog_drafts/func_801802BC.c", "binary": "ov_SC06_008", "source": "worker", "residual": null, "passes_tried": null}
+730 -732
View File
File diff suppressed because it is too large Load Diff
+29 -29
View File
@@ -4,16 +4,16 @@
# cross-binary collapsible-byte leverage: docs/duplicates.cross.md.
# THREE progress metrics (all matter — see the labels):
FLEET fn-count byte-ident: 351170 / 363163 = 96.70% (REAL+LINKED+empties; FUNCTION-count, ×134-inflated — one crack counts per overlay)
FLEET instr-weighted : 12887186 / 13523865 = 95.3% (shipped .text across main + resident + 211 overlays; the decomp.dev-DISPLAY number)
FLEET distinct-code(uniq): 5270302 / 5851972 = 90.1% (81429/90929 unique fns; the DISTINCT-RE number)
FLEET fn-count byte-ident: 351202 / 363163 = 96.71% (REAL+LINKED+empties; FUNCTION-count, ×134-inflated — one crack counts per overlay)
FLEET instr-weighted : 12888121 / 13523865 = 95.3% (shipped .text across main + resident + 211 overlays; the decomp.dev-DISPLAY number)
FLEET distinct-code(uniq): 5271237 / 5851972 = 90.1% (81461/90929 unique fns; the DISTINCT-RE number)
MAIN game-code weighted : 436 / 79510 = 0.5% (INCLUDED in the fleet numbers above since 2026-07-22 — roadmap §1 metrics contract; LINKED-excluding Ghidra sig dated 2026-08-05; caveat is R34: no independent second oracle for a PS-X EXE, NOT drift)
(fleet EXCLUDING main, for continuity with pre-2026-07-22 readings: 12886750 / 13444355 = 95.9%)
(fleet EXCLUDING main, for continuity with pre-2026-07-22 readings: 12887685 / 13444355 = 95.9%)
FLEET REAL substantive : 349000 (of which dedup-shared 254465 via 2072 groups / 254541 instances)
FLEET REAL substantive : 349032 (of which dedup-shared 254465 via 2072 groups / 254541 instances)
FLEET LINKED PsyQ objs : 959
FLEET NON_MATCHING : 7 (0 in any default build — G4)
FLEET INCLUDE_ASM stubs : 11986
FLEET INCLUDE_ASM stubs : 11954
FLEET matchable : 363163
| binary | REAL | shared | LINKED | byte-ident | matchable | byte-ident % |
@@ -92,9 +92,9 @@ FLEET matchable : 363163
| md_SC07_004 | 43 | 0 | 0 | 43 | 315 | 13.7% |
| ov_MAIN_012 | 2236 | 1689 | 0 | 2315 | 2403 | 96.3% |
| ov_SC01_000 | 2390 | 1809 | 0 | 2390 | 2403 | 99.5% |
| ov_SC01_001 | 2400 | 1811 | 0 | 2402 | 2466 | 97.4% |
| ov_SC01_001 | 2401 | 1811 | 0 | 2403 | 2466 | 97.4% |
| ov_SC01_004 | 2399 | 1802 | 0 | 2400 | 2414 | 99.4% |
| ov_SC01_005 | 2437 | 1829 | 0 | 2437 | 2503 | 97.4% |
| ov_SC01_005 | 2439 | 1829 | 0 | 2439 | 2503 | 97.4% |
| ov_SC01_006 | 2437 | 1829 | 0 | 2437 | 2503 | 97.4% |
| ov_SC01_008 | 2400 | 1803 | 0 | 2402 | 2426 | 99.0% |
| ov_SC01_009 | 2428 | 1803 | 0 | 2429 | 2507 | 96.9% |
@@ -106,7 +106,7 @@ FLEET matchable : 363163
| ov_SC02_003 | 2533 | 1854 | 0 | 2533 | 2683 | 94.4% |
| ov_SC02_004 | 2391 | 1806 | 0 | 2391 | 2401 | 99.6% |
| ov_SC02_005 | 2546 | 1802 | 0 | 2556 | 2927 | 87.3% |
| ov_SC02_011 | 2646 | 1810 | 0 | 2656 | 2893 | 91.8% |
| ov_SC02_011 | 2647 | 1810 | 0 | 2657 | 2893 | 91.8% |
| ov_SC02_015 | 2402 | 1808 | 0 | 2402 | 2414 | 99.5% |
| ov_SC02_016 | 2485 | 1810 | 0 | 2488 | 2545 | 97.8% |
| ov_SC02_017 | 2558 | 1810 | 0 | 2566 | 2732 | 93.9% |
@@ -120,15 +120,15 @@ FLEET matchable : 363163
| ov_SC02_039 | 2397 | 1806 | 0 | 2397 | 2416 | 99.2% |
| ov_SC02_041 | 2493 | 1806 | 0 | 2496 | 2561 | 97.5% |
| ov_SC03_001 | 2699 | 1807 | 0 | 2716 | 2869 | 94.7% |
| ov_SC03_002 | 2550 | 1815 | 0 | 2565 | 2631 | 97.5% |
| ov_SC03_002 | 2551 | 1815 | 0 | 2566 | 2631 | 97.5% |
| ov_SC03_003 | 2402 | 1806 | 0 | 2403 | 2423 | 99.2% |
| ov_SC03_006 | 2571 | 1814 | 0 | 2580 | 2767 | 93.2% |
| ov_SC03_007 | 2469 | 1806 | 0 | 2473 | 2623 | 94.3% |
| ov_SC03_007 | 2470 | 1806 | 0 | 2474 | 2623 | 94.3% |
| ov_SC03_010 | 2422 | 1807 | 0 | 2422 | 2471 | 98.0% |
| ov_SC03_011 | 2426 | 1807 | 0 | 2432 | 2527 | 96.2% |
| ov_SC03_012 | 2391 | 1806 | 0 | 2392 | 2406 | 99.4% |
| ov_SC03_013 | 2427 | 1807 | 0 | 2427 | 2493 | 97.4% |
| ov_SC03_014 | 2596 | 1841 | 0 | 2596 | 2685 | 96.7% |
| ov_SC03_014 | 2598 | 1841 | 0 | 2598 | 2685 | 96.8% |
| ov_SC03_015 | 2375 | 1841 | 0 | 2375 | 2468 | 96.2% |
| ov_SC03_023 | 2404 | 1806 | 0 | 2405 | 2435 | 98.8% |
| ov_SC03_024 | 2530 | 1813 | 0 | 2537 | 2641 | 96.1% |
@@ -153,7 +153,7 @@ FLEET matchable : 363163
| ov_SC03_103 | 2497 | 1808 | 0 | 2500 | 2510 | 99.6% |
| ov_SC03_104 | 2551 | 1811 | 0 | 2558 | 2616 | 97.8% |
| ov_SC03_105 | 2452 | 1807 | 0 | 2459 | 2597 | 94.7% |
| ov_SC03_107 | 2308 | 1689 | 0 | 2391 | 2497 | 95.8% |
| ov_SC03_107 | 2310 | 1689 | 0 | 2393 | 2497 | 95.8% |
| ov_SC03_108 | 2406 | 1806 | 0 | 2406 | 2443 | 98.5% |
| ov_SC03_109 | 2409 | 1807 | 0 | 2411 | 2424 | 99.5% |
| ov_SC03_110 | 2444 | 1830 | 0 | 2444 | 2468 | 99.0% |
@@ -163,15 +163,15 @@ FLEET matchable : 363163
| ov_SC03_114 | 2391 | 1806 | 0 | 2393 | 2415 | 99.1% |
| ov_SC03_115 | 2437 | 1806 | 0 | 2439 | 2472 | 98.7% |
| ov_SC03_116 | 2404 | 1806 | 0 | 2407 | 2438 | 98.7% |
| ov_SC03_117 | 2483 | 1806 | 0 | 2489 | 2557 | 97.3% |
| ov_SC03_118 | 2571 | 1840 | 0 | 2572 | 2684 | 95.8% |
| ov_SC03_117 | 2484 | 1806 | 0 | 2490 | 2557 | 97.4% |
| ov_SC03_118 | 2575 | 1840 | 0 | 2576 | 2684 | 96.0% |
| ov_SC03_119 | 2569 | 1840 | 0 | 2570 | 2685 | 95.7% |
| ov_SC03_121 | 2407 | 1807 | 0 | 2409 | 2459 | 98.0% |
| ov_SC03_124 | 2597 | 1802 | 0 | 2617 | 2741 | 95.5% |
| ov_SC03_125 | 2534 | 1815 | 0 | 2546 | 2588 | 98.4% |
| ov_SC03_126 | 2404 | 1808 | 0 | 2404 | 2423 | 99.2% |
| ov_SC04_000 | 2478 | 1811 | 0 | 2487 | 2546 | 97.7% |
| ov_SC04_002 | 2518 | 1806 | 0 | 2522 | 2636 | 95.7% |
| ov_SC03_125 | 2535 | 1815 | 0 | 2547 | 2588 | 98.4% |
| ov_SC03_126 | 2405 | 1808 | 0 | 2405 | 2423 | 99.3% |
| ov_SC04_000 | 2479 | 1811 | 0 | 2488 | 2546 | 97.7% |
| ov_SC04_002 | 2519 | 1806 | 0 | 2523 | 2636 | 95.7% |
| ov_SC04_003 | 2443 | 1813 | 0 | 2446 | 2502 | 97.8% |
| ov_SC04_004 | 2475 | 1807 | 0 | 2477 | 2558 | 96.8% |
| ov_SC04_005 | 2512 | 1806 | 0 | 2518 | 2612 | 96.4% |
@@ -180,12 +180,12 @@ FLEET matchable : 363163
| ov_SC04_008 | 2402 | 1806 | 0 | 2402 | 2415 | 99.5% |
| ov_SC04_009 | 2428 | 1806 | 0 | 2431 | 2441 | 99.6% |
| ov_SC04_010 | 2405 | 1806 | 0 | 2406 | 2419 | 99.5% |
| ov_SC04_011 | 2523 | 1811 | 0 | 2529 | 2803 | 90.2% |
| ov_SC04_011 | 2524 | 1811 | 0 | 2530 | 2803 | 90.3% |
| ov_SC04_012 | 2402 | 1806 | 0 | 2403 | 2420 | 99.3% |
| ov_SC04_015 | 2545 | 1807 | 0 | 2556 | 2611 | 97.9% |
| ov_SC04_016 | 2402 | 1806 | 0 | 2404 | 2440 | 98.5% |
| ov_SC04_018 | 2710 | 1861 | 0 | 2710 | 2857 | 94.9% |
| ov_SC04_019 | 2705 | 1861 | 0 | 2705 | 2857 | 94.7% |
| ov_SC04_016 | 2403 | 1806 | 0 | 2405 | 2440 | 98.6% |
| ov_SC04_018 | 2714 | 1861 | 0 | 2714 | 2857 | 95.0% |
| ov_SC04_019 | 2706 | 1861 | 0 | 2706 | 2857 | 94.7% |
| ov_SC04_020 | 2520 | 1815 | 0 | 2532 | 2567 | 98.6% |
| ov_SC04_021 | 2403 | 1808 | 0 | 2403 | 2423 | 99.2% |
| ov_SC05_000 | 2407 | 1810 | 0 | 2410 | 2422 | 99.5% |
@@ -204,23 +204,23 @@ FLEET matchable : 363163
| ov_SC05_018 | 2553 | 1814 | 0 | 2566 | 2673 | 96.0% |
| ov_SC05_019 | 2403 | 1808 | 0 | 2403 | 2423 | 99.2% |
| ov_SC06_000 | 2543 | 1817 | 0 | 2546 | 2691 | 94.6% |
| ov_SC06_006 | 2432 | 1807 | 0 | 2433 | 2511 | 96.9% |
| ov_SC06_008 | 2501 | 1808 | 0 | 2507 | 2542 | 98.6% |
| ov_SC06_006 | 2433 | 1807 | 0 | 2434 | 2511 | 96.9% |
| ov_SC06_008 | 2502 | 1808 | 0 | 2508 | 2542 | 98.7% |
| ov_SC06_010 | 2473 | 1806 | 0 | 2478 | 2517 | 98.5% |
| ov_SC06_011 | 2417 | 1806 | 0 | 2421 | 2468 | 98.1% |
| ov_SC06_011 | 2418 | 1806 | 0 | 2422 | 2468 | 98.1% |
| ov_SC06_013 | 2407 | 1806 | 0 | 2408 | 2425 | 99.3% |
| ov_SC06_014 | 2418 | 1806 | 0 | 2420 | 2453 | 98.7% |
| ov_SC06_015 | 2412 | 1806 | 0 | 2412 | 2421 | 99.6% |
| ov_SC06_016 | 2455 | 1807 | 0 | 2457 | 2549 | 96.4% |
| ov_SC06_018 | 2550 | 1807 | 0 | 2557 | 2665 | 95.9% |
| ov_SC06_018 | 2551 | 1807 | 0 | 2558 | 2665 | 96.0% |
| ov_SC06_020 | 2472 | 1808 | 0 | 2473 | 2518 | 98.2% |
| ov_SC06_022 | 2523 | 1806 | 0 | 2531 | 2642 | 95.8% |
| ov_SC06_024 | 2542 | 1806 | 0 | 2548 | 2667 | 95.5% |
| ov_SC06_025 | 2454 | 1806 | 0 | 2459 | 2572 | 95.6% |
| ov_SC06_027 | 2392 | 1806 | 0 | 2393 | 2408 | 99.4% |
| ov_SC06_029 | 2479 | 1807 | 0 | 2491 | 2662 | 93.6% |
| ov_SC06_029 | 2480 | 1807 | 0 | 2492 | 2662 | 93.6% |
| ov_SC06_030 | 2415 | 1807 | 0 | 2415 | 2456 | 98.3% |
| ov_SC06_032 | 2534 | 1807 | 0 | 2541 | 2658 | 95.6% |
| ov_SC06_032 | 2535 | 1807 | 0 | 2542 | 2658 | 95.6% |
| ov_SC06_033 | 2531 | 1807 | 0 | 2538 | 2631 | 96.5% |
| ov_SC07_000 | 2439 | 1811 | 0 | 2441 | 2521 | 96.8% |
| ov_SC07_001 | 2407 | 1807 | 0 | 2409 | 2454 | 98.2% |
+7
View File
@@ -63,11 +63,18 @@ R22 clean-fleet **213/213** after every banked batch · tools-health green · 0
|---|---|--:|--:|--:|--:|--:|---|
| A | adapt SMALL-EDIT | 24 | 18 (75%) | **12** (+1 prop) | ~1.40M | **~117k** | zero stale seed-symbols (the §171 prompt-law works); 6 gate-fails all INTEGRATION shapes (3× decl-type vs TU, 1 arity, 2 TU-context DIFF) → wave-B prompt adds match-the-TU's-existing-decl |
| grinder-1 | permuter | 10 | — | 0 | $0 | — | func_800CB4CC parked at best-1 (warmstart seed); queue enriched +59+6 records since |
| C-probe | tell (3) | 3 | 1 (33%) | **1** | ~300k | ~300k | §174 **Law 4**: the TU's decl of YOUR OWN fn constrains the def sig — standalone MATCH gated 0/1 until canonical-sig + cast-at-use; tell attribution unreliable (2/3 residuals were a different class) |
| C | tell 11 + weak 24 | 35 | **35 (100%)** | **32** (8 propagated ×2) | ~2.39M | ~75k | Law 4 in-prompt → 0 symbol fails, 91% gate; **weak lane 24/24 on haiku — the 890-card vein is live**; 3 NEAR → grinder |
- 2026-08-14 — **CAMPAIGN OPEN (T10+, Ultracode).** Wave A: 24 adapt cards → 18/24 standalone (75%) → symfix-first (0 stale — the prompt-law worked) → gate **12 banked + 1 propagation** (~117k tok/bank e2e; stubs → 12,030). 6 NEARs (3 at close ≤3) enqueued to the grinder. Wave B (48 cards, all haiku, 29 binaries) launched with the decl-matching lesson. Grinder pass 1: 0/10 but func_800CB4CC at best-1.
- 2026-08-14 (resume session) — **Checkpoint resume steps 1–2 DONE.** (1) **R22 owed proof banked: `make clean && make extract-all && make check-all` → 213 passed, 0 failed of 213** (`.run/r22_p31_resume.log` EXIT=0) — wave B's banks verified fleet-clean. (2) **`make atlas` regenerated at HEAD `commit:2234`**: 363,525 feature rows / 92,855 distinct bodies (0 newly computed — memo hit); **5,144 groups / 11,994 open instances / 612,325 ins**; warm merges 1,014; seeded 4,710/7,247 skeletons; all assertions green. Open count 12,058→11,994 reconciles with the session's 65 banks. (3) Wave C fuel verified: `.run/wave_p31c_cards.json` = 38 cards (14 tell/sonnet + 24 weak/haiku); grinder idle (heartbeat `done`); gate free. Drew's re-extraction question answered (disc/splat layers gain nothing — deterministic + continuously regenerated; sig/atlas layer regenerated by this step; Ghidra-C re-analysis = targeted-probe candidate only, R37). NOTE: this harness build has no TaskCreate tool — this checklist + log is the monitorable task view (R28 noted plainly).
- 2026-08-14 (resume session, cont.) — **WAVE C COMPLETE: 32 banked, R22 213/213.** Probe→wave cadence (§174 law 3) paid: the 3-card probe cost ~300k tok and returned Law 4, which the 35-card wave then converted at 91% gate with zero symbol failures. Independent re-verify of all 35 drafts by me (R14) before gating: 35/35 MATCH held. **Reach measured honestly: 32 exemplars, only 8 had any sharer, each ×2 → ~1.25× effective.** The ×134 era is over (P25/29/30 harvested the shared cores); fleet-% now moves ~1:1 with exemplars banked, so THROUGHPUT is the lever, not leverage.
- **THREE instrument defects found+fixed in my own new tooling this cycle** (the R32/R35/R39 class, and the reason R39 exists): (1) `build_wave.py`'s gate-guard used `pgrep -f` via `shell=True` — the wrapping `sh -c` carries the pattern in its own cmdline so it self-matched and refused forever; fixed by invoking pgrep without a shell. (2) The open-stub predicate did `fn in corpus.stubs(binary)` — but `stubs()` returns **addr→Stub**, so every card looked "already-banked" and BOTH pools reported ~0 candidates (I nearly concluded the 622-card adapt pile and 954-card weak pile were spent). Fixed to `{st.symbol for st in ...values()}` and **negative-controlled against the known population** (35 wave-C cards, 32 banked → exactly 3 still open: PASS). (3) I fired wave D once with hand-typed placeholder card names instead of the generated file — caught and stopped within a minute, relaunched from `.run/wave_p31d_args.json`. Recorded, not buried (P9).
- **Pools are NOT spent (post-fix, honest): adapt 569 candidates, weak 890 candidates.**
- **STRATEGIC (Drew's question "why are our waves so weak?" — he is right):** the card lanes I have been drawing from are the *mechanical leftovers* (12–42-ins cousins), ≈1,400 ins/wave against 612,325 open ins ≈ **0.23%/wave**. The Atlas already maps where the mass actually is: **head-crack 1,276 groups / 4,248 inst / 186,291 ins** (≈3.3 inst per group — a group head crack banks its members), **UNKNOWN 1,964 / 138,597**, extend-tell 575 / 76,730, redraft 280 / 46,769, jtbl-carve 190 / 45,673. And high-reach groups DO remain: gid `96f8b78ec8d3` = **265 instances / 6,084 ins** (integration lever, 31-ins exemplar), `75cec648ba15` = 116 inst / 3,002 ins, `152d63c1086d` = 64 inst / 1,559 ins. **Next: build the wave generator off `.run/atlas.json` groups (top instruction-mass first, routed by the group's measured lever) instead of the leftover card piles.**
## Blockers
(none)
+97
View File
@@ -0,0 +1,97 @@
#!/usr/bin/env python3
"""Build the next campaign wave from a card pool (adapt | weak), in the proven wave-B shape.
Selection: still an open stub (derived from the corpus oracle, R32/R33 — never a stale label),
not already spent in a prior wave, ranked by fleet leverage (reach desc, then similarity desc).
Model routed by size per the subagent ladder (haiku <=50 ins, sonnet 51-120); larger is left to a
targeted lane, not a bulk wave.
MUST be run with NO gate in flight — gate_lane transiently substitutes drafts into src/, so a
concurrent read of corpus.stubs() reports substituted functions as already-banked (R35).
Usage: build_wave.py <pool: adapt|weak> <out.json> [N]
"""
import json, sys, collections, subprocess
sys.path.insert(0, 'tools')
import corpus
pool = sys.argv[1]
out = sys.argv[2]
n = int(sys.argv[3]) if len(sys.argv) > 3 else 48
# NB: invoke pgrep WITHOUT a shell. With shell=True the wrapping `sh -c` carries the pattern in
# its own command line and pgrep -f matches it — the self-match false positive (cookbook §174
# ops note, same class as the grinder pgrep). pgrep excludes only its own PID, not its parent.
_busy = subprocess.run(['pgrep', '-f', 'tools/(gate_stage|dedup_propagate|gate_lane)'],
capture_output=True, text=True)
if _busy.returncode == 0 and _busy.stdout.strip():
sys.exit(f"REFUSING: a gate is in flight (pids {_busy.stdout.split()}) — corpus.stubs() would "
f"misreport substituted drafts as banked (R35). Wait for it.")
PRIORS = ['.run/wave_p31a_cards.json', '.run/wave_p31b_cards.json', '.run/wave_p31c_cards.json',
'.run/wave_p31d_cards.json', '.run/wave_p31e_cards.json', '.run/wave_p31f_cards.json',
'.run/wave_p31g_cards.json', '.run/wave_p31h_cards.json']
taken = set()
for p in PRIORS:
try:
taken |= {c.get('fn') or c.get('name') for c in json.load(open(p))}
except (FileNotFoundError, json.JSONDecodeError):
pass
src = {'adapt': '.run/adapt_cards.json', 'weak': '.run/weak_cards.json'}[pool]
cards = json.load(open(src))
_open = {}
def is_open(binary, fn):
if binary not in _open:
# corpus.stubs() is addr -> Stub; the NAME lives on the record (R35: I read the
# container, not the contract, and every card looked 'already-banked')
_open[binary] = {st.symbol for st in corpus.stubs(binary).values()}
return fn in _open[binary]
def model_for(nins):
if not nins: return 'haiku'
if nins <= 50: return 'haiku'
if nins <= 120: return 'sonnet'
return None
sel, skipped = [], collections.Counter()
for c in cards:
fn = c.get('fn') or c.get('name')
binary = c['binary']
if pool == 'adapt' and c.get('klass') != 'SMALL-EDIT':
skipped['not-small-edit'] += 1; continue
if fn in taken:
skipped['already-waved'] += 1; continue
m = model_for(c.get('nins'))
if not m:
skipped['too-big-for-wave'] += 1; continue
if not is_open(binary, fn):
skipped['already-banked'] += 1; continue
rec = {'fn': fn, 'binary': binary, 'lane': pool, 'model': m,
'nins': c.get('nins'), 'sim': c.get('sim'), 'reach': c.get('reach'),
'sub': c.get('sub'), 'addr': c.get('addr')}
if pool == 'adapt':
rec.update(klass=c.get('klass'),
seed_path=(c.get('seed') or {}).get('path'),
seed_kind=(c.get('seed') or {}).get('kind'),
seed_name=(c.get('seed') or {}).get('name'),
sites=[{'at': d.get('member_at'), 'kind': d.get('kind'),
'member': d.get('member_disasm', []), 'seed': d.get('seed_disasm', [])}
for d in (c.get('diff') or [])])
else:
rec.update(seed=c.get('seed'), note=c.get('note'), unit_ins=c.get('unit_ins'))
sel.append(rec)
sel.sort(key=lambda c: (-(c.get('reach') or 0), -(c.get('sim') or 0)))
wave = sel[:n]
json.dump(wave, open(out, 'w'), indent=1)
print(f"pool={pool} total={len(cards)} candidates={len(sel)} skipped={dict(skipped)} -> wave {len(wave)} -> {out}")
if wave:
print("models:", dict(collections.Counter(c['model'] for c in wave)))
ni = [c['nins'] for c in wave if c.get('nins')]
if ni: print(f"nins {min(ni)}-{max(ni)}")
print("binaries:", len({c['binary'] for c in wave}))
json.dump([{'fn': c['fn'], 'binary': c['binary'], 'lane': c['lane'], 'model': c['model'],
'sim': c.get('sim'), 'seed_path': c.get('seed_path'), 'seed_name': c.get('seed_name')}
for c in wave], open(out.replace('.json', '_index.json'), 'w'))