Files
BFM-decomp/.run/w6.js
T
Drew T 139e21118b docs(phase-30 S38): wave 6 launched — pool derivation is a script now, + 2 derive-don't-assert fixes
- .run/w6_pool.py: THE pool derivation, finally a script instead of inline python (R33).
  Ranks by OPEN templatable weight (corpus.stubs over the family map's member list, §138 rule 4 —
  never off the map's `exemplar` field), carries the walls/ledgered-residual exclusion set, drops
  any family whose address was attempted-and-still-open in a prior wave (83 addrs), and enforces
  one target per (overlay, TU) so a wave cannot manufacture its own §138-rule-2 type-tag conflict.
  Pool: 2,928 fresh families / 476,611 open templatable ins.
- wave 6 = 16 targets / 50,596 open templatable ins (3x wave 5), large-function heavy
  (median ~270 ins, max 947); prompt carries the S37/W6 block (stage the big ones; cross-address
  families need STEP 0 because searching by address cannot find their twin; the PAIR rule).
- TWO R37 FIXES TO THE MANIFEST ITSELF, both "asserted, never derived":
  * `seed` was an arbitrary i%2 alternation carried over from the previous wave's shape — it
    controls whether the prompt claims a cached Ghidra seed EXISTS. Now derived from
    .run/ghidra_c/ on disk: 9 of 16, not 8 by alternation.
  * `model` routed by MEASURED band, not the stale §136i ladder: Sonnet is measured 81-100%
    first-pass over 125-793 ins, so func_8017C974 (947) is outside it and goes to Opus directly.
- CURRENT_PHASE.md: in-flight checkpoint (the wave-5 restart lost 2.7M tokens of ungated drafts;
  this block says force-add the drafts and resume by GATING, never by re-running).
2026-08-04 16:13:14 -06:00

153 lines
24 KiB
JavaScript

export const meta = {
name: 'p30-w6-pipeline',
description: 'P30 wave 6: fresh h_seq families, open sites DERIVED from corpus.stubs (50,596 templ ins)',
phases: [
{ title: 'Draft', detail: 'one agent per target, size-routed per the §136i ladder (haiku/sonnet/opus)' },
{ title: 'Escalate', detail: 'next rung up (haiku->sonnet, sonnet->opus) on any non-MATCH' },
],
}
// args = { targets: [...compact records...], extra: "<idioms promoted from the previous wave>" }
// Accept a JSON string too — an invocation can deliver args stringified and pipeline() then dies.
const A = {targets: [{"fn": "func_8017C974", "ov": "ov_SC01_077", "sub": "asm/ov_SC01_077/nonmatchings/ov_SC01_077_jr_8017AE2C", "tu": "src/ov_SC01_077/ov_SC01_077_jr_8017AE2C.c", "n": 947, "m": 16, "ti": 15152, "diff": "PURE", "tag": "cross-address", "model": "opus", "seed": 1}, {"fn": "func_8017FEE0", "ov": "ov_SC02_026", "sub": "asm/ov_SC02_026/nonmatchings/ov_SC02_026_jr_8017C180", "tu": "src/ov_SC02_026/ov_SC02_026_jr_8017C180.c", "n": 299, "m": 20, "ti": 5980, "diff": "PURE", "tag": "scattered", "model": "sonnet", "seed": 1}, {"fn": "func_80181CE4", "ov": "ov_SC03_111", "sub": "asm/ov_SC03_111/nonmatchings/ov_SC03_111_jr_8017EC58", "tu": "src/ov_SC03_111/ov_SC03_111_jr_8017EC58.c", "n": 491, "m": 7, "ti": 3437, "diff": "PURE", "tag": "cross-address", "model": "sonnet", "seed": 1}, {"fn": "func_80189030", "ov": "ov_SC03_001", "sub": "asm/ov_SC03_001/nonmatchings/ov_SC03_001_jr_8017AE2C", "tu": "src/ov_SC03_001/ov_SC03_001_jr_8017AE2C.c", "n": 557, "m": 5, "ti": 2785, "diff": "PURE", "tag": "cross-address", "model": "sonnet", "seed": 1}, {"fn": "func_80188C68", "ov": "ov_SC03_124", "sub": "asm/ov_SC03_124/nonmatchings/ov_SC03_124_jr_8017AE2C", "tu": "src/ov_SC03_124/ov_SC03_124_jr_8017AE2C.c", "n": 551, "m": 5, "ti": 2755, "diff": "PURE", "tag": "cross-address", "model": "sonnet", "seed": 0}, {"fn": "func_8018A564", "ov": "ov_SC02_027", "sub": "asm/ov_SC02_027/nonmatchings/ov_SC02_027_jr_8017D898", "tu": "src/ov_SC02_027/ov_SC02_027_jr_8017D898.c", "n": 125, "m": 22, "ti": 2750, "diff": "PURE", "tag": "scattered", "model": "sonnet", "seed": 0}, {"fn": "func_801878E8", "ov": "ov_SC04_018", "sub": "asm/ov_SC04_018/nonmatchings/ov_SC04_018_jr_8017AE2C", "tu": "src/ov_SC04_018/ov_SC04_018_jr_8017AE2C.c", "n": 513, "m": 5, "ti": 2565, "diff": "PURE", "tag": "cross-address", "model": "sonnet", "seed": 0}, {"fn": "func_801884D8", "ov": "ov_SC02_028", "sub": "asm/ov_SC02_028/nonmatchings/ov_SC02_028_jr_8017D898", "tu": "src/ov_SC02_028/ov_SC02_028_jr_8017D898.c", "n": 137, "m": 15, "ti": 2055, "diff": "PURE", "tag": "scattered", "model": "sonnet", "seed": 0}, {"fn": "func_801380E0", "ov": "ov_SC07_006", "sub": "asm/ov_SC07_006/nonmatchings/ov_SC07_006_jr_80135D20", "tu": "src/ov_SC07_006/ov_SC07_006_jr_80135D20.c", "n": 438, "m": 4, "ti": 1752, "diff": "PURE", "tag": "per-location", "model": "sonnet", "seed": 1}, {"fn": "func_8017EA84", "ov": "ov_SC02_000", "sub": "asm/ov_SC02_000/nonmatchings/ov_SC02_000_jr_8017AE2C", "tu": "src/ov_SC02_000/ov_SC02_000_jr_8017AE2C.c", "n": 579, "m": 3, "ti": 1737, "diff": "PURE", "tag": "cross-address", "model": "sonnet", "seed": 1}, {"fn": "func_80184C74", "ov": "ov_SC06_018", "sub": "asm/ov_SC06_018/nonmatchings/ov_SC06_018_jr_8017C24C", "tu": "src/ov_SC06_018/ov_SC06_018_jr_8017C24C.c", "n": 288, "m": 6, "ti": 1728, "diff": "PURE", "tag": "cross-address", "model": "sonnet", "seed": 1}, {"fn": "func_801841C8", "ov": "ov_SC02_035", "sub": "asm/ov_SC02_035/nonmatchings/ov_SC02_035_jr_8017BEBC", "tu": "src/ov_SC02_035/ov_SC02_035_jr_8017BEBC.c", "n": 44, "m": 39, "ti": 1716, "diff": "IMM", "tag": "scattered", "model": "sonnet", "seed": 0}, {"fn": "func_80183AE0", "ov": "ov_SC03_112", "sub": "asm/ov_SC03_112/nonmatchings/ov_SC03_112_jr_8017C294", "tu": "src/ov_SC03_112/ov_SC03_112_jr_8017C294.c", "n": 240, "m": 7, "ti": 1680, "diff": "PURE", "tag": "cross-address", "model": "sonnet", "seed": 0}, {"fn": "func_80180F98", "ov": "ov_SC03_097", "sub": "asm/ov_SC03_097/nonmatchings/ov_SC03_097_jr_8017D898", "tu": "src/ov_SC03_097/ov_SC03_097_jr_8017D898.c", "n": 263, "m": 6, "ti": 1578, "diff": "PURE", "tag": "cross-address", "model": "sonnet", "seed": 1}, {"fn": "func_80180B04", "ov": "ov_SC06_020", "sub": "asm/ov_SC06_020/nonmatchings/ov_SC06_020_jr_8017C24C", "tu": "src/ov_SC06_020/ov_SC06_020_jr_8017C24C.c", "n": 251, "m": 6, "ti": 1506, "diff": "PURE", "tag": "cross-address", "model": "sonnet", "seed": 1}, {"fn": "func_801919A0", "ov": "ov_SC06_032", "sub": "asm/ov_SC06_032/nonmatchings/ov_SC06_032_jr_8017C24C", "tu": "src/ov_SC06_032/ov_SC06_032_jr_8017C24C.c", "n": 710, "m": 2, "ti": 1420, "diff": "PURE", "tag": "cross-address", "model": "sonnet", "seed": 0}], extra: "START HERE \u2014 SIBLING-FIRST IS THE FASTEST ROUTE (\u00a7136c, measured this session: it produced several\nFIRST-DRAFT matches). Before you derive anything from the .s:\n 1. grep src/shared/engine_core.h for a `DEFINE_func_*` macro body that is a NEAR-TWIN of your\n target (same struct-offset chain, same shape, differing only in constants/one call). This is a\n family wave \u2014 the twin usually EXISTS, because that is what a family is.\n 2. grep your own TU for an already-BANKED sibling (a real function definition, not an INCLUDE_ASM).\n 3. Reuse its EXPRESSION FORMS and its DECLARATION FORMS verbatim. They are already byte-proven to\n produce the gcc-2.7.2 schedule and register assignment you need.\nSearch order: engine_core.h near-twin -> same-TU banked sibling -> the .s -> the Ghidra seed LAST\n(the seed was byte-proven to be an ENTIRELY DIFFERENT body twice this session).\n\nTHE LOCAL-VARIABLE LEVER (\u00a7136 \u2014 highest-yield finding, 25 banks). gcc-2.7.2 allocates ONE PSEUDO\nPER C LOCAL, and local-alloc.c:472 REFUSES a local allocno whose REG_N_DEATHS > 1 \u2014 promoting it to\na GLOBAL allocno that loses the low register. The number and scope of your locals moves whole\nregister assignments. REACH FOR THIS BEFORE register __asm__ PINS.\n L1. Same $v0/$v1 pair swapped in ONE arm only => you reused ONE local across N arms. SPLIT it into\n per-arm block-scoped locals.\n L2. One extra `sw $sN` in the prologue, frame otherwise identical => SPLIT a compound initializer:\n `x = *(u8*)p << k;` makes TWO pseudos; `x = *(u8*)p; x = x << k;` reuses one.\n L3. An extra `addu $vX,$v0,$zero` after a `jal` AND a later copy of the same value => the source\n had TWO variables with the first PINNED (an unpinned pseudo coalesces the pair away).\n L4. LENGTH-DRIFT short by `addiu $sN,$sp,K` + a save/restore pair => write a POINTER local assigned\n before the loop and used only inside it.\n L5. Local stack slots are assigned in DECLARATION order ascending from 0x10, independent of use\n order. Frame-offset drift with correct code is a declaration-ORDER problem.\n\nTYPE-FORM RULES:\n T1. A real `mult $rX,$rY` with a small constant => the multiplier is a NON-CONST LOCAL, not a\n literal (a literal goes through synth_mult's sll/addu chain). `s32 r = K;` as its own statement.\n T2. `li $sN,0xfff0` + `addu` where the target has `addiu $vN,$vN,-0x10` => gcc narrowed to HImode.\n Hoist the call to its own statement; put the load+subtract in a BLOCK-SCOPED s32 temp.\n T3. `andi $vN,0xffff` after a `jal` the target lacks => the TU declares that callee u16/s16-\n returning. Do NOT change the decl \u2014 cast at the call (idiom 9 on the RETURN axis).\n T4. Unexplained `addu $vX,$aY,$zero` near a conditional branch (including in its DELAY SLOT,\n consumed only by the fall-through arm) + the feeding `lh` loads out of order => the value is an\n s16 LOCAL, not s32; LOAD_EXTEND_OP folded the widening extend into a plain move.\n T5. LENGTH-DRIFT +1 with a narrow load of the SAME stack slot => gcc narrowed a memory-operand\n `local >> 16`. Bind the local to an s32 temp used twice.\n T6. A symbol read once at a constant offset but built into $s1 by lui/addiu => cache it in a\n POINTER LOCAL. A direct D_xxx[k] folds %lo per use and shrinks the frame.\n T7. BRANCH POLARITY: if match_one prints BRANCH-POLARITY, invert the source condition \u2014 gcc-2.7.2\n flips the branch to place the longer block as the fall-through. (Closed 8 mismatches in one\n edit this wave; the index keys the literal string \"BRANCH-POLARITY\" straight to \u00a73-T4.)\n\nSCHEDULING:\n S1. The MEM_IN_STRUCT_P escape does NOT apply when the blocking store has a VARYING (register-base)\n address \u2014 true_dependence() only drops the edge for a CONSTANT-address store. Then the lever is\n SOURCE ORDER: assign the load to a temp ABOVE the stores. (But same-base `reg+const` addresses\n ARE disambiguated by memrefs_conflict_p, so those hoists are free.)\n S2. An unfilled load-delay nop where the target fills it with a trailing call's arg setup => hoist a\n LOAD: split `*p = *p + 1` into `v = *p + 1; ... *p = v;`.\n S3. NEVER pin an incoming PARAMETER \u2014 it turns the param's `move` into a schedulable body insn and\n reshuffles the whole prologue. Pin loop variables only.\n S4. If no C lever moves a 3-6 instruction schedule/regalloc residual, a \u00a721 ZERO-BYTE RE-TIE\n barrier can anchor it: `__asm__ __volatile__(\"\" : \"=r\"(v) : \"0\"(v));` between the loads and the\n use. Try the source-level levers first; this closed one case after six other variants failed.\n\nDECLARATION SURFACE (decides whether a byte-correct draft BANKS):\n D1. `conflicting types` for a D_ symbol you cannot find declared in the split .c => the decl lives\n inside a DEFINE_func_*() MACRO BODY in src/shared/engine_core.h. Reuse its canonical type.\n An 8-byte-stride table declared `s32 D_x[][2]` must be indexed [i][0]/[i][1].\n D2. cc1 reports only the FIRST conflict. EVERY reconciled draft this session had a SECOND hidden\n conflict, sometimes BELOW the splice point. grep the WHOLE TU in ONE pass for every symbol.\n D3. A DECLARATION CONFLICT ABORTS THE COMPILE, so it hides the byte question entirely. If you are\n handed a draft as \"byte-correct, only declaration-blocked\", RUN match_one ON IT FIRST \u2014 two of\n three such drafts this session also had a real codegen residual behind the conflict.\n D4. If you compile anything, use a PROCESS-UNIQUE scratch path. A shared one silently compiled\n another agent's file and returned a meaningless success this session.\n\n\nx2-9 BAND. \u00a7136c sibling-first still applies but CHECK the twin EXISTS first (\u00a7136e) \u2014 if the whole\nfamily is in nonmatchings, go straight to the .s. \u00a7136j: sub-120-ins targets tend to fail on\nDECLARATIONS, 120+ on real codegen; do the whole-TU one-pass symbol grep (D2) either way.\nIf match_one reports REGALLOC-PERM (a clean 2-register swap), see \u00a7137: it is a TWO-COMPILE\nARITHMETIC problem \u2014 read R and L from `cc1 -dl -dg`, evaluate floor_log2(R)*R/L*1e4*size for both\ncontenders AND their ranked neighbours to get the admissible window, then place a zero-byte\n`__asm__ __volatile__(\"\" ::\"r\"(v))` so L lands inside it. Do NOT reach for the permuter first.\n\n\nS33 MEASURED (promote into your first pass):\n - \u00a7138 RECONCILE DIRECTION: if the TU declares your symbol ABOVE the splice point, DELETE your\n duplicate; if BELOW, KEEP a decl in the TU's EXACT shape and cast at the use. Picking the wrong\n direction CREATES the next error. grep the TU for the symbol and compare line numbers with the\n stub line BEFORE editing either way.\n - A repeated typedef OR a repeated bare `struct Tag {...}` is a C89 ERROR even when textually\n identical. If the TU already defines the type trio you copied from a sibling, do not redeclare\n it \u2014 and check for the bare struct tag too, not just the typedefs (that one cost an extra round).\n - func_8017D174 (793 ins) closed a \u00a7137 allocno tie AND a sched2 loop-head rotation JOINTLY with\n four zero-byte asms: two `\"=r\"`/`\"0\"` re-ties splitting a live range, plus two volatile sliders\n placed in a DIFFERENT basic block, so they lift the live-length count without perturbing the head\n schedule. A slider inside the block you are trying to fix will regress it.\n - Rank/trust nothing from a map's `exemplar` field: derive the open sites from corpus.stubs. The\n map's exemplar can point at an instance that is ALREADY banked, which hides the whole family.\n\n\nS34 MEASURED \u2014 DO THIS FIRST:\n - STEP 0 of sibling-first, ahead of engine_core.h: `grep -rn \"<MAGIC>\" src/` with a distinctive\n literal from YOUR .s (a magic word, an unusual mask, an odd immediate). \u00a7136c's first two steps\n are same-TU/shared-header scoped and CANNOT reach a banked twin in another overlay's TU \u2014 and the\n big template classes live cross-overlay. Measured: func_80188C04 (328 ins) was byte-identical to\n an already-banked func_801833F0 in ov_SC02_028; one grep found it and the body was reused\n verbatim with only file-local type/macro suffixes renamed.\n - If a sibling of yours banked into the SAME TU recently, the TU now carries ITS type names for the\n shared data symbols. Use the TU's names; do not introduce your own suffixed duplicates.\n - \"normalized distance 0\" is NOT an h_exact guarantee. Relocs are masked by normalization.\n\n\nS35 (wave 3 banked 13/13 \u2014 the magic-grep STEP 0 is doing the work; lead with it):\n - Write ONLY your deliverable `.run/<wave>/<ov>/func_<ADDR>.c` into the drafts directory. Scratch\n files there break the gate. Put experiments anywhere else under .run/.\n - If the TU declares your function itself incompatibly (`extern void f(void);` vs a def that takes\n an argument), that is the SELF axis: define under a private C name bound to the real symbol \u2014\n `extern <ret> aF<ADDR>(<args>) __asm__(\"func_<ADDR>\"); <ret> aF<ADDR>(<args>) { ... }`. Three of\n this session's reconciles were exactly this, and it has zero blast radius on callers.\n\n\nS36: STEP 0 is now the highest-yield move in this prompt \u2014 waves 3 and 4 both banked 100% and most\nagents reported `index_gap: none` because the grep resolved the target in one pass. LEAD WITH IT.\n - If two targets in your wave share a TU, the FIRST one banked puts its file-local type tags into\n that TU. If you copy a sibling's body, do NOT also copy its `struct X_<ADDR> {...}` definition \u2014\n the TU may already have it ABOVE your splice point, and a repeated tag is a C89 error even when\n identical. Use the TU's tag; delete your duplicate (\u00a7138 reconcile direction).\n\n\nS37/W6 MEASURED \u2014 wave 5 banked 16/16 with ZERO post-gate reconciles, which means these rules land:\n - STEP 0 (the magic-literal grep of src/) is STILL the single highest-yield move. LEAD WITH IT.\n - THIS WAVE IS LARGE-FUNCTION HEAVY: median ~270 instructions, several 490-947. Two consequences:\n (a) budget the read \u2014 go through the whole .s once for structure (frame, callee-saved set, jal\n targets, every %hi/%lo symbol) BEFORE writing a line; a 500-ins body written from a partial\n read gets rewritten, not repaired;\n (b) close in STAGES. Get the control-flow structure and call sequence exact first (match_one will\n show a large but STRUCTURED residual), then work the register/schedule residual with the L*/\n S* levers. A structure error and a regalloc error look alike at high closeness numbers and\n are fixed by opposite edits.\n - MOST OF THIS WAVE IS addr_tag=cross-address: your family's twin sits at a DIFFERENT ADDRESS in\n another overlay. Searching by address will NOT find it; the STEP-0 magic-literal grep WILL. This\n is exactly the case STEP 0 was invented for \u2014 do not skip it because the address looks unfamiliar.\n - A GATE REFUSAL IS A (macro-shape, TU-shape) PAIR, NOT A SYMBOL. The same symbol conflicts in BOTH\n directions across the fleet: a macro may declare it `(u8*)` while your TU says `(void)`, or the\n mirror. Read the decl of the MACRO YOU ARE ACTUALLY USING \u2014 not of its sibling \u2014 and reconcile by\n the \u00a7138 direction rule (TU decl ABOVE the splice => delete your duplicate; BELOW => keep a decl\n in the TU's EXACT shape and cast at the use).\n - THREE CARRY VARIANTS hide behind one \"it compiled standalone\" \u2014 and gcc-2.7.2 accepts implicit\n function declarations, so the third passes compiles_standalone and only fails the byte-gate:\n a multi-line comment in the preamble, a draft-local `struct Tag {...}` (use the SHARED type from\n engine_types.h instead), and a file-scope `static inline` helper. If your body needs a file-scope\n helper or a private type, say so in your summary \u2014 that routes it correctly instead of silently\n failing 137 gates later.\n"}
const T = Array.isArray(A) ? A : A.targets
const EXTRA = (Array.isArray(A) ? '' : A.extra) || ''
if (!Array.isArray(T)) throw new Error('args.targets must be an array')
const VERDICT = {
type: 'object',
additionalProperties: false,
required: ['fn', 'status', 'summary'],
properties: {
fn: { type: 'string' },
status: { type: 'string', enum: ['MATCH', 'DIFF', 'BLOCKED'] },
closeness: { type: 'number', description: 'mismatching instructions remaining; 0 for MATCH' },
klass: { type: 'string', description: 'residual class if not MATCH' },
summary: { type: 'string', description: 'what you did and what the residual is, <=4 sentences' },
levers: { type: 'string', description: 'cookbook sections / idioms that CLOSED the residual' },
index_hit: { type: 'boolean' },
index_gap: { type: 'string' },
},
}
function prompt(t, escalated) {
const asm = `${t.sub}/${t.fn}.s`
return `You are matching ONE PS1 function to byte-identical gcc-2.7.2 output for the Brave Fencer
Musashi decompilation. Your ONLY deliverable is a C file at \`.run/w6/${t.ov}/${t.fn}.c\`.
TARGET
function ${t.fn}
binary ${t.ov}
target asm ${asm} <- THE GROUND TRUTH. Read this FIRST and in full.
TU it lands in ${t.tu}
asm-subdir ${t.sub}
size ${t.n} instructions
leverage family of ${t.m} members / ${t.ti} templatable instructions — a byte-match here
propagates ${t.m}x across the fleet.
${t.seed ? ` ghidra seed .run/ghidra_c/${t.fn}.c <- A HINT ONLY. It is sometimes an ENTIRELY
DIFFERENT body (byte-proven this phase). If it disagrees with the .s, THE .s WINS.` : ` ghidra seed (none cached — work from the .s)`}
${t.retry ? ` ** RETRY ** A previous wave recorded: "${t.retry}". That is a data point, not a
verdict. Re-derive from the .s; do not assume the earlier verdict was right.` : ''}
HOW TO WORK (this order is the measured-fastest)
1. \`docs/cookbook-index.md\` is a SYMPTOM-KEYED index of 364 byte-verified idioms. Grep it for your
residual's symptom BEFORE deriving anything. Measured: index-first took a wave's bank rate from
57% to 100%. Then read the section it names in \`docs/matching-cookbook.md\`.
\`docs/gcc-2.7.2-map/{sched,regalloc,loop,cse_expr}.md\` is the compiler-source-derived map for
scheduling / register-allocation residuals.
2. Read the target \`.s\` completely: frame size, callee-saved registers, jal targets, every
\`%hi/%lo\` symbol.
3. Read the TU (${t.tu}) for EVERY symbol your draft will name. cc1 reports only the FIRST conflict,
so a draft can look one edit from done and hold three more. grep the whole TU in ONE pass.
Match its existing declarations EXACTLY; push any type disagreement to a CAST AT THE USE SITE
rather than redeclaring the symbol.
4. Write the draft, then verify:
.venv/bin/python tools/match_one.py ${t.fn} --c .run/w6/${t.ov}/${t.fn}.c --asm-subdir ${t.sub}
Iterate until it prints MATCH; it names the exact mismatching instructions.
IDIOMS THAT CLOSED RESIDUALS IN THE LAST WAVES (cookbook §135 — all byte-verified)
1. UNSIGNED switch index => pure equality chain, NO range test. No \`slti\` bound check in the
target's switch means the index is u32, not s32.
2. \`a0[0x46]\` (ARRAY_REF) sets MEM_IN_STRUCT_P and lets a load HOIST past a constant-address
store; \`*(s16 *)((s32)a0 + 0x8C)\` (INDIRECT_REF) keeps the dependence. Many 4-instruction
"scheduling residuals" are just this type-form choice.
3. A constant store whose top bit is set in the STORED width needs an UNSIGNED destination:
\`*(u16 *)p = 0x8C00\` emits \`ori\`; through \`s16\` it folds negative and emits \`addiu\`.
4. The list scheduler PRESERVES the relative order of disambiguable stores. A store written late
in source SINKS. If a store lands too late, move it EARLIER IN SOURCE (not a permuter job).
5. A \`short\` loop counter blocks strength reduction; walking explicit pointers (\`p++\`)
reproduces the original biv/giv set.
6. Frame size off by a constant => DEAD LOCALS. If ALL diffs are \`sp\`-relative immediates off by
one constant delta, add the padding declaration.
7. An INTERIOR address has no symbol — a \`lui/addiu\` pair can build an offset INTO a symbol.
Find the containing symbol in the data \`.s\` and index into it; declaring the interior address
as its own extern link-fails.
8. NEVER redeclare a C-library name (\`memcpy\` etc.).
9. Loose typing is pervasive: if the TU declares \`void f(void)\` but the asm passes \`$a0\`, call
through a cast — \`((void(*)(s32))f)(a0)\` — do NOT change the declaration.
${EXTRA ? `\nPROMOTED FROM THE PREVIOUS BATCH (fresh, byte-verified this session)\n${EXTRA}\n` : ''}
HARD RULES
* Write ONLY \`.run/w6/${t.ov}/${t.fn}.c\`. NEVER edit \`src/\`, \`asm/\`, \`config/\`, \`include/\`,
the Makefile, or any tracked file.
* Do NOT run \`make\`, \`make build\`, \`make extract\`, or \`tools/harvest_verify.py\`. The
whole-binary gate is the orchestrator's job and the sole arbiter of a match.
* \`match_one\` MATCH is NECESSARY BUT NOT SUFFICIENT — it compiles standalone and cannot see the
TU's other declarations. Step 3 is what makes a MATCH actually BANK.
* Report honestly. A DIFF with a precise residual class routes the next attempt; a false MATCH
just gets caught by the byte-gate and wastes a cycle.
* ${escalated ? 'A cheaper rung of the model ladder already attempted this and did not reach MATCH. Read its draft at the path above, but re-derive from the .s rather than trusting it.' : 'Work economically — most functions this size close from the .s plus one or two index lookups.'}
Return the structured verdict.`
}
phase('Draft')
// S36 MEASUREMENT: the two-batch `parallel()` design was a HARD BARRIER — batch 2 could not start
// until batch 1's slowest agent finished. Measured across waves 1-4 from agent transcript
// timestamps: median agent 9-33 min but wall-clock 125-208 min, i.e. only 2.1-4.8x effective
// parallelism, with 37-50 min dead gaps visible at every batch boundary. 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-14 targets — so it bought nothing and cost a barrier.
// pipeline() has NO barrier: each target flows draft -> escalate independently, so wall-clock is
// the slowest SINGLE chain rather than the sum of two batch maxima.
const results = await pipeline(
T,
(t) => agent(prompt(t, false), {
label: `draft:${t.fn}(${t.n}i,x${t.m})`,
phase: 'Draft',
model: t.model,
schema: VERDICT,
}).then((v) => ({ t, v })),
async ({ t, v }) => {
if (!v) return { t, v: { fn: t.fn, status: 'BLOCKED', summary: 'agent returned no verdict' }, tier: t.model }
if (v.status === 'MATCH' || t.model === 'opus') return { t, v, tier: t.model }
const nextTier = t.model === 'haiku' ? 'sonnet' : 'opus'
const v2 = await agent(prompt(t, true), {
label: `escalate:${t.fn}`,
phase: 'Escalate',
model: nextTier,
schema: VERDICT,
})
return { t, v: v2 && v2.status === 'MATCH' ? v2 : (v2 || v), tier: nextTier + '-escalated' }
},
)
const ok = results.filter(Boolean)
const matched = ok.filter((r) => r.v && r.v.status === 'MATCH')
log(`w6-wave: ${matched.length}/${T.length} claim MATCH (the gate is the arbiter)`)
return {
claimed_match: matched.map((r) => r.t.fn),
verdicts: ok.map((r) => ({
fn: r.t.fn, ov: r.t.ov, nins: r.t.n, members: r.t.m, tier: r.tier,
status: r.v ? r.v.status : 'NONE',
closeness: r.v ? r.v.closeness : null,
klass: r.v ? r.v.klass : null,
levers: r.v ? r.v.levers : null,
index_hit: r.v ? r.v.index_hit : null,
index_gap: r.v ? r.v.index_gap : null,
summary: r.v ? r.v.summary : null,
})),
}