Files
BFM-decomp/.run/s8_reconcile.js
T
Drew T a4bc49a23d feat(phase-30 S8): the x10-99 band closes 23/23; §137 makes REGALLOC-PERM arithmetic, not a permuter job
- S8-3 (23 fresh x10-99 families, 121-328 ins — the hardest band this session): draft 16/23 ->
  capture (1 PLUMBING / 6 DIFF) -> reconcile 1/1 -> redraft 6/6 => **23/23 (100%)**.
  Propagated 206 + 81 = 287 member-matches across 80+54 overlays. R22 clean-fleet 140/140.
  FLEET 95.97% fn / 93.4% instr / 87.5% distinct (77,404 uniq); dedup 1905/0; 0 NON_MATCHING.
- §136b CLOSES AT 15/15 — no function ledgered "genuine byte-DIFF" survived a redraft, all session.
- §137 (NEW, the session's most reusable result): REGALLOC-PERM — a clean 2-register swap — is a
  TWO-COMPILE ARITHMETIC PROBLEM. global.c:allocno_compare ranks by floor_log2(R)*R/L*1e4*size;
  read R and L out of `cc1 -dl -dg` for BOTH contenders AND their ranked neighbours to get the
  admissible priority WINDOW, then place a zero-byte `__asm__ __volatile__("" ::"r"(v))` so L lands
  inside it. func_801833F0: contenders ONE unit apart (1297 vs 1296), window (1228,1296), five
  placements probed, only L=219 -> pri 1232 worked. R and L are FORCED BY THE EMITTED CODE (L is
  recomputed post-sched1), which is exactly why source-reordering is a dead end for this class.
  Converts a class the permuter banked 0 from all session into a deterministic calculation.
  Companion: floor_log2 makes ref-count a STEP function (5/6/7 refs are worthless, you must reach 8)
  — func_8017EFA8 closed 30 register-name mismatches by taking a pseudo 4 refs -> 8 with a dead read.
- §136j — the failure MIX FLIPS WITH SIZE: <=120 ins fails ~70% on declarations; 121-328 ins fails
  86% on genuine codegen. Budget reconcile for the small band, redraft for the big one — and do NOT
  read 70% on a big-function wave as a broken pipeline; that is the expected shape.
- §137a — a gate verdict has a TIMESTAMP. Two "DIFF" ledger entries were STALE (draft rewritten 28
  min after the gate ran, never re-gated); both were already byte-perfect. Compare verdict time to
  draft mtime before redrafting. Plus two offline oracles an agent built: a FULL RELOCATION RESOLVE
  (catches wrong jal/%hi/%lo targets that match_one's mask hides) and a COLLATERAL CHECK (whole-TU
  objdump with/without splice). Together they discriminate all three causes of "match_one says MATCH
  but the overlay SHA differs" without running make.
- §136f addendum — the collider is often an already-banked SIBLING BELOW the splice; locate it by
  arithmetic (draft grows the file N lines, so TU line L reports at L+N).
- cookbook-index 380 -> 382 sections.
2026-08-03 16:25:06 -06:00

91 lines
4.8 KiB
JavaScript

export const meta = {
name: 'p30-s8-reconcile',
description: 'P30 wave 4a reconcile lane: fix the 7 declaration-blocked drafts (blockers captured)',
phases: [{ title: 'Reconcile', detail: 'one Opus agent per PLUMBING failure, blocker line embedded' }],
}
const A = [{"fn": "func_801832A8", "ov": "ov_SC02_026", "tu": "src/ov_SC02_026/ov_SC02_026_jr_8017C180.c", "sub": "asm/ov_SC02_026/nonmatchings/ov_SC02_026_jr_8017C180", "blocker": "src/ov_SC02_026/ov_SC02_026_jr_8017C180.c:5030: conflicting types for `func_8012BE98' || src/ov_SC02_026/ov_SC02_026_jr_8017C180.c:4745: previous declaration of `func_8012BE98' || src/ov_SC02_026/ov_SC02_026_jr_8017C180.c:5031: conflicting types for `func_8012B744' || src/ov_SC02_026/ov_SC02_026_jr_8017C180.c:4746: previous declaration of `func_8012B744'", "no_build": false}]
const T = Array.isArray(A) ? A : A.targets
if (!Array.isArray(T)) throw new Error('args must be an array of targets')
const VERDICT = {
type: 'object',
additionalProperties: false,
required: ['fn', 'status', 'summary'],
properties: {
fn: { type: 'string' },
status: { type: 'string', enum: ['FIXED', 'STILL-BLOCKED', 'DIFF'] },
lever: { type: 'string', description: 'which byte-neutral lever closed it' },
summary: { type: 'string' },
index_gap: { type: 'string' },
},
}
phase('Reconcile')
const results = await pipeline(T, (t) =>
agent(`A byte-correct C draft is being REFUSED by the whole-binary byte-gate for a DECLARATION
reason, not a codegen reason. Fix the declarations. Do NOT rewrite the function body unless you
prove it is actually wrong.
function ${t.fn}
binary ${t.ov}
draft .run/s8/${t.ov}/${t.fn}.c <- edit THIS FILE IN PLACE; it is your only deliverable
TU ${t.tu}
asm-subdir ${t.sub}
target asm ${t.sub}/${t.fn}.s
THE COMPILER'S OWN ERROR, captured by splicing your draft into the TU and building ${t.ov}:
${t.blocker}
You cannot run the gate yourself — that error line IS the evidence. Without it this reads like a
codegen wall; with it, this lane has closed 12 of 12 across the last two waves.
THE TWO BYTE-NEUTRAL LEVERS (use these; do NOT edit any shared header)
(A) **Conform the declaration, cast at the USE site.** When the conflict is on a symbol OTHER than
the function you are defining: copy the TU's existing declaration VERBATIM into your draft, and
push every type disagreement to a cast at the call/use site —
\`((s32(*)(s32))func_X)(a)\` for a call, \`*(T *)&D_Y\` for data. Zero bytes change.
(B) **The §37/§124 asm-label alias**, when the conflict is on the function you are DEFINING (its
return type or arity disagrees with a banked caller's declaration):
\`<ret> aF${t.fn.replace('func_', '')}(<params>) __asm__("${t.fn}");\`
and define that alias instead. It sidesteps the collision at ZERO blast radius. The data form
exists too: \`extern struct B16_x aD800A5E88 __asm__("D_800A5E88");\`
CRITICAL — cc1 reports only the FIRST conflict, so more may hide behind this one. **grep the WHOLE
TU (including BELOW your splice point) for EVERY symbol your draft names, in one pass**, and
reconcile them all at once. One wave-2 draft had invented prototypes for six symbols the TU already
declared, two of them below the splice point.
Never redeclare a C-library name (\`memcpy\` etc.) — one TU declares it three incompatible ways.
VERIFY: \`.venv/bin/python tools/match_one.py ${t.fn} --c .run/s8/${t.ov}/${t.fn}.c --asm-subdir ${t.sub}\`
must still report MATCH after your edit. If it does NOT, your declaration change altered codegen —
back it out and use a cast instead.
${t.no_build ? `⚠️ **DO NOT RUN ANY BUILD** (\`make\`, \`make build\`). Another agent is reconciling a
different function in this SAME TU concurrently, and two splice-builds would clobber a tracked file.
\`match_one\` is fine — it uses a private scratch dir.` : `You may run \`match_one\` freely. Do NOT run \`make build\` or \`harvest_verify\` — the orchestrator gates.`}
Write ONLY \`.run/s8/${t.ov}/${t.fn}.c\`. Never edit src/, asm/, config/, include/, or the Makefile.
If after honest work the residual turns out to be a real byte difference rather than a declaration
problem, say so (status DIFF) with the evidence — that routes it correctly and is worth more than a
forced fix.`, {
label: `reconcile:${t.fn}`,
phase: 'Reconcile',
model: 'opus',
schema: VERDICT,
}).then((v) => ({ t, v })),
)
const ok = results.filter(Boolean)
log(`reconcile: ${ok.filter((r) => r.v && r.v.status === 'FIXED').length}/${T.length} claim FIXED`)
return {
fixed: ok.filter((r) => r.v && r.v.status === 'FIXED').map((r) => r.t.fn),
verdicts: ok.map((r) => ({ fn: r.t.fn, ov: r.t.ov, status: r.v && r.v.status,
lever: r.v && r.v.lever, summary: r.v && r.v.summary,
index_gap: r.v && r.v.index_gap })),
}