mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-10-07 09:27:55 -04:00
feat(tools): the Claude-subagent wave harness promoted from the T4 probe — claude_wave_packs.py (identical api_agent packs), workflows/claude_wave_draft.js + claude_wave_distill.js (the 60-agent draft and the R16 distill scripts), wave_judge.py (per-arm whole-binary gate with git-diff bank detection, tree reset, --union); SETUP row (P31 S62)
This commit is contained in:
@@ -736,6 +736,7 @@ Every script under `tools/` (plus the two report make-targets), grouped by purpo
|
||||
| | `tools/stub_invariant_audit.py` | **(Phase 31 S62 T1, cookbook §301)** Regression test for the masked comparer: INCLUDE_ASM pastes the original bytes, so `diff_object_s(object, .s)` must be 0 for every stub; quotes the denominator (stubs with internal-`j` relocs). Run after ANY change to `masked_diff.py`. |
|
||||
| | `tools/interleave_check.py` | **(Phase 31 S62 T2, cookbook §302)** Order ⇔ yaml consistency for an overlay's jtbl carve: the `_JTBL_INTERLEAVE` order must equal the yaml subseg sequence position by position. `--fix` regenerates the order from the yaml (never hand-edit it). Run after ANY restore of overlays.mk or a splat yaml (two of the five S61 reds and four of the six clean-sweep failures were exactly this). |
|
||||
| | `tools/pads_audit.py` | **(Phase 31 S62 T2, cookbook §302)** DERIVES each object's `JTBL_PADS` from the bytes: compiles the TU to count its tables, walks the retail words inside the yaml carve with those sizes (pad 4 ⇔ one zero word), reports SPEC-DRIFT / CARVE-DRIFT / ok with the derived spec. Reproduced 15/15 correct specs as its negative control; replaced S61's blind value searches. |
|
||||
| | `tools/claude_wave_packs.py` · `tools/workflows/claude_wave_draft.js` · `tools/wave_judge.py` | **(Phase 31 S62 T4)** The Claude-subagent wave harness that ran the model-ladder probe: identical packs from `api_agent` (SYS + user_msg + law-1c warm start + gate feedback) → a Workflow of drafting agents per (arm, fn) with CLI equivalents of grep/read_file/match_one/submit, writing only under `.run/<wave>/<arm>/` → `wave_judge.py` gates each arm with `sweep_parallel` (banked = removed INCLUDE_ASM lines in `git diff`; tree reset between arms; `--union` leaves the cheapest winning drafts in the tree). `tools/workflows/claude_wave_distill.js` = the R16 distill (extract per byte-proven transcript → verify vs the cookbook). Routing rule from T4: ≤50 Sonnet, 51–120 Sonnet, >120 Opus, Opus on residue; haiku retired; DeepSeek optional at ~$0.03/fn. |
|
||||
| | `tools/jtbl_rodata_pads.py --derive` | **(Phase 31 S62 T3a, cookbook §303)** Module path of the §8e pads filter: the Makefile runs `--derive $(BINARY) --tu <tu>` for every `md_*` object — jump-table pads derived at build time from the retail island + the emission stream (trailing pads `0t1`, table-aware, const data passes through). No stored spec; an anchor miss fails the build with the offset. |
|
||||
| | `tools/blocker_probe.py` | **(Phase 29 SESSION-16, cookbook §65)** WHY a byte-correct draft fails the whole-binary gate. Read-only; **two oracles** (R34): STATIC (`cdecl.parse` + `cdecl.compatible` — cc1's own acceptance question, never text equality) beside the REAL cc1 (via `rtu_match`), leading with the DISAGREEMENT table. Classes `self_decl_hdr`/`self_decl_tu`/`callee_decl`/`data_decl`/`local_type`, each mapped to a blast-radius tier (T0 draft-only / T1 binary-local / T2 fleet-shared). Blockers STACK, so a function's tier is the MAX over them. 36 drafts in ~9 s. Replaced+deleted `.run/diag_plumbing.py`. |
|
||||
| | `tools/symcheck.py` | **(Phase 29 SESSION-18, cookbook §67a)** The pre-gate SYMBOL-SET guard: diffs the symbols a draft's object references (reloc records) against the target `.s`'s `%hi`/`%lo`/`jal` set. Catches the class **every masked oracle is structurally blind to** — `match_one`/`masked_diff` compare relocation-MASKED words (object-vs-`.s` mode is symbol-agnostic by construction) and `rtu_match` **compiles without linking**, so a draft that invents an extern no symbol table defines reads MATCH in both and can never bank (the SESSION-17 `func_801463A0` `_s`-alias trap). Negative-control-proven: on a draft with one renamed data extern, `match_one` reports the SAME 14 mismatched as the correct draft while `symcheck` exits 1 naming both the MISSING and the INVENTED symbol. `--c` (compiles via `match_one`, so the triple can never drift) or `--obj`. A cheap necessary condition, NOT a match oracle — still finish on the byte-gate (G3/P9). |
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env python3
|
||||
"""tools/claude_wave_packs.py — build the per-function PACKS a Claude-subagent wave drafts from (P31 S62 T4).
|
||||
|
||||
The pack is EXACTLY what tools/api_agent.py sends a paid model: api_agent.user_msg(target, card) +
|
||||
prior_draft (law-1c filtered: symbols must overlap the target .s) + gate_feedback, plus api_agent.SYS
|
||||
written once. Identical packs are what made the T4 arms comparable; keep it that way.
|
||||
|
||||
Usage: claude_wave_packs.py <targets.json> <out_dir> [--cards cards.json]
|
||||
targets.json: [{name, binary, nins, sub, asm, tu}, ...] (api_agent's target shape; see
|
||||
tools/main_queue_rebuild.py / .run/t4/targets.json for how to derive one from corpus)
|
||||
out_dir/SYS.md + out_dir/packs/<fn>.md are produced; the workflow script
|
||||
tools/workflows/claude_wave_draft.js points its agents at them (edit REPO/paths at the top).
|
||||
Then: Workflow(scriptPath=tools/workflows/claude_wave_draft.js, args={targets:[{name,binary,nins,sub}...]})
|
||||
-> drafts in .run/<wave>/<arm>/<fn>.c -> tools/wave_judge.py <arms...> [--union] (whole-binary gate,
|
||||
banked = removed INCLUDE_ASM lines in git diff; tree reset between arms; --union leaves the best
|
||||
cheapest arm's drafts in the tree for the commit). Routing rule measured in T4 (CURRENT_PHASE S62):
|
||||
<=50 ins Sonnet (+DeepSeek if funded), 51-120 Sonnet, >120 Opus, Opus on every residue."""
|
||||
import sys, os, json, glob
|
||||
REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__))); os.chdir(REPO)
|
||||
sys.path.insert(0, 'tools')
|
||||
for k, v in (('API_BASE', 'x'), ('API_KEY', 'x'), ('MODEL', 'x'), ('MAXTOK', '8000')):
|
||||
os.environ.setdefault(k, v)
|
||||
import api_agent as A
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 3:
|
||||
sys.exit(__doc__)
|
||||
targets = json.load(open(sys.argv[1])); out = sys.argv[2]
|
||||
cards = {}
|
||||
if '--cards' in sys.argv:
|
||||
for c in json.load(open(sys.argv[sys.argv.index('--cards') + 1])):
|
||||
if c.get('fn'): cards[c['fn']] = c
|
||||
else: # newest per-fn card across every wave card file
|
||||
for f in sorted(glob.glob('.run/wave_*_cards.json'), key=os.path.getmtime):
|
||||
try:
|
||||
for e in json.load(open(f)):
|
||||
if isinstance(e, dict) and e.get('fn'): cards[e['fn']] = e
|
||||
except Exception:
|
||||
pass
|
||||
os.makedirs(os.path.join(out, 'packs'), exist_ok=True)
|
||||
open(os.path.join(out, 'SYS.md'), 'w').write(A.SYS)
|
||||
n = 0
|
||||
for t in targets:
|
||||
um = A.user_msg(t, cards.get(t['name']))
|
||||
pd, where = A.prior_draft(t)
|
||||
if pd:
|
||||
um += ("\n\nA PREVIOUS ATTEMPT on this exact function left this body behind (%s). The whole-binary "
|
||||
"byte-gate did NOT accept it, so it is wrong somewhere — but it is usually wrong in ONE place; "
|
||||
"keep what matches the .s, fix what does not. Discard it if it is a different function's body."
|
||||
"\n\n```c\n" % where) + pd.strip() + "\n```\n"
|
||||
gf = A.gate_feedback(t)
|
||||
if gf:
|
||||
um += '\n\n' + gf + '\n'
|
||||
open(os.path.join(out, 'packs', t['name'] + '.md'), 'w').write(um); n += 1
|
||||
print('packs: %d written to %s (cards matched %d/%d)' % (n, out, sum(1 for t in targets if t['name'] in cards), len(targets)))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env python3
|
||||
"""T4 judge — per-arm whole-binary gate (G3/P9, exit codes checked per R53), tree reset between arms,
|
||||
then the union (best arm per fn) gated once and left in the tree for the commit. Reads targets from
|
||||
.run/t4/targets.json and drafts from .run/t4/<arm>/<fn>.c. Writes .run/t4/judge.json.
|
||||
Usage: judge.py [arms...] (default haiku sonnet opus ds)"""
|
||||
import sys, os, json, glob, subprocess, shutil, time
|
||||
REPO = '/home/musashi/bfm-decomp'; os.chdir(REPO)
|
||||
sys.path.insert(0, 'tools'); import corpus
|
||||
UNION = '--union' in sys.argv
|
||||
ARMS = [a for a in sys.argv[1:] if not a.startswith('--')] or ['haiku', 'sonnet', 'opus', 'ds']
|
||||
targets = json.load(open('.run/t4/targets.json'))
|
||||
T = {t['name']: t for t in targets}
|
||||
def sh(cmd, timeout=3600):
|
||||
return subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)
|
||||
def open_fns():
|
||||
out = {}
|
||||
for b in {t['binary'] for t in targets}:
|
||||
s = corpus.stubs(b); out[b] = {x.symbol for x in (s.values() if isinstance(s, dict) else s)}
|
||||
return out
|
||||
def reset_tree():
|
||||
sh(['git', 'checkout', '-q', '--', 'src/', 'config/']); sh(['git', 'clean', '-fq', 'src/'])
|
||||
r = sh(['git', 'status', '--porcelain', '--', 'src/', 'config/'])
|
||||
assert not r.stdout.strip(), 'tree not clean after reset:\n' + r.stdout
|
||||
def stage(arm, fns):
|
||||
d = '.run/t4/stage_%s' % arm; shutil.rmtree(d, ignore_errors=True)
|
||||
n = 0
|
||||
for fn in fns:
|
||||
src = '.run/t4/%s/%s.c' % (arm, fn)
|
||||
if not os.path.exists(src) or os.path.getsize(src) == 0: continue
|
||||
b = T[fn]['binary']; os.makedirs('%s/%s' % (d, b), exist_ok=True)
|
||||
shutil.copy(src, '%s/%s/%s.c' % (d, b, fn)); n += 1
|
||||
return d, n
|
||||
def gate(arm, fns):
|
||||
before = open_fns()
|
||||
d, n = stage(arm, fns)
|
||||
if n == 0: return {}, 'no drafts'
|
||||
bins = ','.join(sorted({T[f]['binary'] for f in fns if os.path.exists('.run/t4/%s/%s.c' % (arm, f))}))
|
||||
t0 = time.time()
|
||||
r = sh(['flock', '.run/auto/draw.lock', '.venv/bin/python', 'tools/sweep_parallel.py', '--drafts', d, '--only', bins, '-j', '4'], 7200)
|
||||
open('.run/t4/gate_%s.log' % arm, 'w').write(r.stdout + r.stderr)
|
||||
# banked = INCLUDE_ASM lines the gate removed (git diff; immune to corpus's per-process cache)
|
||||
d = sh(['git', 'diff', '-U0', '--', 'src/']).stdout
|
||||
import re as _re
|
||||
removed = set(_re.findall(r'^-INCLUDE_ASM\("[^"]+",\s*(func_\w+)\);', d, _re.M))
|
||||
banked = {fn for fn in fns if fn in removed}
|
||||
return banked, 'rc=%d %ds %d staged' % (r.returncode, time.time() - t0, n)
|
||||
def main():
|
||||
reset_tree()
|
||||
res = {'arms': {}, 'fns': {}}
|
||||
if os.path.exists('.run/t4/judge.json'):
|
||||
old = json.load(open('.run/t4/judge.json')); res['arms'] = old.get('arms', {})
|
||||
for a, v in res['arms'].items():
|
||||
for f in v.get('banked', []): res['fns'].setdefault(f, []).append(a)
|
||||
for arm in ARMS:
|
||||
fns = [t['name'] for t in targets]
|
||||
banked, note = gate(arm, fns)
|
||||
res['arms'][arm] = {'banked': sorted(banked), 'n_banked': len(banked), 'drafts': sum(1 for f in fns if os.path.exists('.run/t4/%s/%s.c' % (arm, f))), 'note': note}
|
||||
print('%-7s banked %2d / %2d drafts (%s)' % (arm, len(banked), res['arms'][arm]['drafts'], note), flush=True)
|
||||
for f in banked: res['fns'].setdefault(f, []).append(arm)
|
||||
reset_tree()
|
||||
# union: cheapest winning arm per fn (ladder order), gated once and LEFT IN THE TREE for the commit
|
||||
order = ['haiku', 'sonnet', 'ds', 'opus']
|
||||
pick = {}
|
||||
for f, arms in res['fns'].items():
|
||||
pick[f] = sorted(arms, key=lambda a: order.index(a) if a in order else 99)[0]
|
||||
ud = '.run/t4/stage_union'; shutil.rmtree(ud, ignore_errors=True)
|
||||
for f, a in pick.items():
|
||||
b = T[f]['binary']; os.makedirs('%s/%s' % (ud, b), exist_ok=True)
|
||||
shutil.copy('.run/t4/%s/%s.c' % (a, f), '%s/%s/%s.c' % (ud, b, f))
|
||||
if pick and UNION:
|
||||
bins = ','.join(sorted({T[f]['binary'] for f in pick}))
|
||||
r = sh(['flock', '.run/auto/draw.lock', '.venv/bin/python', 'tools/sweep_parallel.py', '--drafts', ud, '--only', bins, '-j', '4'], 7200)
|
||||
open('.run/t4/gate_union.log', 'w').write(r.stdout + r.stderr)
|
||||
d = sh(['git', 'diff', '-U0', '--', 'src/']).stdout
|
||||
import re as _re
|
||||
removed = set(_re.findall(r'^-INCLUDE_ASM\("[^"]+",\s*(func_\w+)\);', d, _re.M))
|
||||
res['union'] = {'picked': pick, 'banked': sorted(f for f in pick if f in removed), 'rc': r.returncode}
|
||||
print('union: %d picked, %d banked (rc=%d) — LEFT IN TREE for the commit' % (len(pick), len(res['union']['banked']), r.returncode))
|
||||
json.dump(res, open('.run/t4/judge.json', 'w'), indent=1)
|
||||
# per-band table (R41: denominators)
|
||||
band = lambda n: '<=50' if n <= 50 else ('51-120' if n <= 120 else '>120')
|
||||
for arm in res['arms']:
|
||||
row = {}
|
||||
for t in targets:
|
||||
k = band(t['nins']); row.setdefault(k, [0, 0]); row[k][1] += 1
|
||||
if t['name'] in res['arms'][arm]['banked']: row[k][0] += 1
|
||||
print('%-7s ' % arm + ' '.join('%s: %d/%d' % (k, v[0], v[1]) for k, v in sorted(row.items())))
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,78 @@
|
||||
export const meta = {
|
||||
name: 't4-idiom-distill',
|
||||
description: 'R16 flywheel: distill the unlocking lesson from each byte-proven T4 transcript, verify novelty against the cookbook, return §-formatted candidates',
|
||||
phases: [
|
||||
{ title: 'Extract', detail: '31 transcripts -> one lesson each' },
|
||||
{ title: 'Verify', detail: 'novel claims grepped against docs/matching-cookbook.md' },
|
||||
],
|
||||
}
|
||||
const REPO = '/home/musashi/bfm-decomp'
|
||||
const WFDIR = '/home/musashi/.claude/projects/-home-musashi-bfm-decomp/b0026d2d-2724-4aed-813a-3deef224d210/subagents/workflows/wf_c691ef44-320/'
|
||||
const LESSON = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
fn: { type: 'string' }, arm: { type: 'string' },
|
||||
title: { type: 'string' },
|
||||
mechanism: { type: 'string' },
|
||||
asm_tell: { type: 'string' },
|
||||
c_shape: { type: 'string' },
|
||||
evidence: { type: 'string' },
|
||||
cookbook_refs_used: { type: 'array', items: { type: 'string' } },
|
||||
novel_claim: { type: 'boolean' },
|
||||
trivial: { type: 'boolean' },
|
||||
},
|
||||
required: ['fn', 'arm', 'title', 'mechanism', 'asm_tell', 'c_shape', 'evidence', 'cookbook_refs_used', 'novel_claim', 'trivial'],
|
||||
}
|
||||
const VERDICT = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
fn: { type: 'string' }, title: { type: 'string' },
|
||||
verdict: { type: 'string', enum: ['COVERED', 'NEW', 'ADDENDUM', 'REFUTED'] },
|
||||
covered_by: { type: 'string' },
|
||||
entry_markdown: { type: 'string' },
|
||||
why: { type: 'string' },
|
||||
},
|
||||
required: ['fn', 'title', 'verdict', 'covered_by', 'entry_markdown', 'why'],
|
||||
}
|
||||
const lessons = await pipeline(
|
||||
args.targets,
|
||||
t => agent(
|
||||
`You are distilling ONE byte-proven decompilation transcript for the project's matching cookbook (docs/matching-cookbook.md, gcc-2.7.2 MIPS idioms). Repo: ${REPO}.
|
||||
Transcript (JSONL, an agent's full tool trace): ${t.transcript.replace("WF/", WFDIR)}
|
||||
Function: ${t.fn} (arm ${t.arm}); the whole-binary byte-gate ACCEPTED the final draft, so the final body is ground truth. The agent's own closing note was: "${t.note}"
|
||||
|
||||
Read the transcript. Find the moment(s) the masked diff (match_one closeness) dropped to 0 and what C change caused it. Report ONE lesson — the most generalizable one — as:
|
||||
title: <=12 words, symptom-keyed (what you see in the diff)
|
||||
mechanism: why gcc-2.7.2 emits it (one or two sentences; say "unknown" honestly if the transcript only shows the fix)
|
||||
asm_tell: the instruction pattern that signals it
|
||||
c_shape: the C construct that reproduces it (a short snippet is fine)
|
||||
evidence: the closeness path (e.g. "closeness 7 -> 0 after X"; quote the exact match_one line(s))
|
||||
cookbook_refs_used: every § the agent grepped/cited that mattered
|
||||
novel_claim: true only if the transcript did NOT get the fix from an existing cookbook §; false if it merely applied one
|
||||
trivial: true if the lesson is "read the asm / fix a typo / use the right symbol" (no compiler law)
|
||||
Read only; write nothing.`,
|
||||
{ label: `extract:${t.arm}:${t.fn}`, phase: 'Extract', model: 'sonnet', schema: LESSON }),
|
||||
(lesson, t) => {
|
||||
if (!lesson || lesson.trivial || !lesson.novel_claim) return lesson ? { ...lesson, verdict: lesson.trivial ? 'TRIVIAL' : 'APPLIED-EXISTING' } : null
|
||||
return agent(
|
||||
`You are the cookbook verifier for the Brave Fencer Musashi decompilation (repo ${REPO}). A distiller claims a NEW gcc-2.7.2 idiom from a byte-proven transcript:
|
||||
fn: ${t.fn} title: ${lesson.title}
|
||||
mechanism: ${lesson.mechanism}
|
||||
asm_tell: ${lesson.asm_tell}
|
||||
c_shape: ${lesson.c_shape}
|
||||
evidence: ${lesson.evidence}
|
||||
refs the agent used: ${JSON.stringify(lesson.cookbook_refs_used)}
|
||||
Check docs/matching-cookbook.md (grep for the mechanism, the instruction pattern, the C construct; docs/cookbook-index.md is symptom-keyed) and decide:
|
||||
COVERED — an existing § already states this law (name it in covered_by)
|
||||
ADDENDUM — an existing § is close but this adds a byte-proven refinement (name it; entry_markdown = a 3-8 line addendum paragraph starting "**Addendum (P31 S62 T4, ${t.fn}):**")
|
||||
NEW — no § states it; entry_markdown = a full section in the book's style, header "## §NNN — <TITLE IN CAPS> (P31 S62 T4; byte-proven ${t.fn})" with NNN left literally as NNN, then the tell, the mechanism, the C shape, the evidence line
|
||||
REFUTED — the claim contradicts a byte-proven § or the evidence does not support it (say why)
|
||||
Quote the § numbers you checked in why. Read only; write nothing.`,
|
||||
{ label: `verify:${t.fn}`, phase: 'Verify', model: 'opus', schema: VERDICT }).then(v => ({ ...lesson, ...(v || { verdict: 'UNVERIFIED', why: 'verifier returned null' }) }))
|
||||
}
|
||||
)
|
||||
const out = lessons.filter(Boolean)
|
||||
const tally = {}
|
||||
for (const l of out) tally[l.verdict] = (tally[l.verdict] || 0) + 1
|
||||
log('verdicts: ' + JSON.stringify(tally))
|
||||
return { lessons: out }
|
||||
@@ -0,0 +1,57 @@
|
||||
export const meta = {
|
||||
name: 't4-model-ladder-probe',
|
||||
description: 'T4 calibration probe: 20 stratified fns x Claude arms (haiku/sonnet/opus) from identical packs; drafts to .run/t4/<arm>/',
|
||||
phases: [
|
||||
{ title: 'Draft', detail: '20 fns x 3 arms = 60 drafting agents, identical packs, local match_one oracle only' },
|
||||
],
|
||||
}
|
||||
const REPO = '/home/musashi/bfm-decomp'
|
||||
const ARMS = [
|
||||
{ arm: 'haiku', model: 'haiku' },
|
||||
{ arm: 'sonnet', model: 'sonnet' },
|
||||
{ arm: 'opus', model: 'opus' },
|
||||
]
|
||||
const TARGETS = args.targets
|
||||
const VERDICT = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
fn: { type: 'string' },
|
||||
arm: { type: 'string' },
|
||||
status: { type: 'string', enum: ['MATCH', 'NEAR', 'FAIL', 'NO-DRAFT'] },
|
||||
closeness: { type: ['integer', 'null'] },
|
||||
compiles: { type: 'boolean' },
|
||||
draft_path: { type: 'string' },
|
||||
note: { type: 'string' },
|
||||
},
|
||||
required: ['fn', 'arm', 'status', 'closeness', 'compiles', 'draft_path', 'note'],
|
||||
}
|
||||
phase('Draft')
|
||||
const jobs = []
|
||||
for (const a of ARMS) for (const t of TARGETS) jobs.push({ a, t })
|
||||
const results = await parallel(jobs.map(({ a, t }) => () => agent(
|
||||
`You are one arm of a controlled calibration probe in the Brave Fencer Musashi decompilation repo at ${REPO}.
|
||||
Byte-match ONE PlayStation function: ${t.name} (${t.nins} instructions, binary ${t.binary}).
|
||||
|
||||
FIRST read these two files in full — they are your complete brief and your ground truth pointers:
|
||||
${REPO}/.run/WAVE/SYS.md (the laws; it names tools read_file/grep/match_one/submit — use the CLI equivalents below)
|
||||
${REPO}/.run/WAVE/packs/${t.name}.md (the target pack: asm path, destination TU, card fuel, a warm-start body, any gate feedback)
|
||||
|
||||
CLI equivalents (run from ${REPO}):
|
||||
read_file -> cat / sed -n
|
||||
grep -> rg or grep -n (start at docs/cookbook-index.md; \`.venv/bin/python tools/cookbook_index.py --resolve N\` resolves a line number)
|
||||
match_one -> .venv/bin/python tools/match_one.py ${t.name} --c <your_draft.c> --asm-subdir ${t.sub} --json
|
||||
(prints JSON with status MATCH/near/... and closeness = masked mismatched instruction count; it is free — use it often)
|
||||
submit -> write your FINAL draft to ${REPO}/.run/WAVE/${a.arm}/${t.name}.c (mkdir -p the dir) and return the JSON verdict.
|
||||
|
||||
HARD RULES: never modify anything under src/, config/, include/, asm/, build/ or run make; never touch other arms' dirs; write only to .run/WAVE/${a.arm}/ and scratch under .run/WAVE/${a.arm}/scratch_${t.name}/. Budget: up to ~24 compile/match_one iterations, then stop honestly.
|
||||
Your final answer is the JSON verdict only: fn, arm="${a.arm}", status (MATCH if match_one says MATCH; NEAR if it compiles with closeness>0; FAIL if it never compiled; NO-DRAFT if you wrote nothing), closeness (integer or null), compiles, draft_path, note (one line: what blocked you, or which cookbook § unlocked it).`,
|
||||
{ label: `${a.arm}:${t.name}`, phase: 'Draft', model: a.model, schema: VERDICT }
|
||||
).then(v => v || { fn: t.name, arm: a.arm, status: 'NO-DRAFT', closeness: null, compiles: false, draft_path: '', note: 'agent returned null' })
|
||||
.catch(e => ({ fn: t.name, arm: a.arm, status: 'NO-DRAFT', closeness: null, compiles: false, draft_path: '', note: 'agent error: ' + String(e).slice(0, 120) }))))
|
||||
const byArm = {}
|
||||
for (const r of results.filter(Boolean)) { (byArm[r.arm] = byArm[r.arm] || []).push(r) }
|
||||
for (const arm of Object.keys(byArm)) {
|
||||
const rs = byArm[arm]
|
||||
log(`${arm}: MATCH ${rs.filter(r => r.status === 'MATCH').length} / NEAR ${rs.filter(r => r.status === 'NEAR').length} / FAIL ${rs.filter(r => r.status === 'FAIL').length} / NO-DRAFT ${rs.filter(r => r.status === 'NO-DRAFT').length} of ${rs.length}`)
|
||||
}
|
||||
return { results }
|
||||
Reference in New Issue
Block a user