Files
stack/agents/darkwing/work/queue-112/r2/mutants.py
T
jason.woltjeandClaude Opus 5.5 fee89d52fe darkwing: row 112 round 2 packet, invalid-options README row (#1606)
README invalid-options cell lists only count, key, text and duplicates; a
non-{key,text} option refuses invalid-request (Sage 28378, Filbert C1 28379).
Broker test pins the option shape cases. m1 and m2 killed; full gate passed
15:53:56-15:59:33Z on BASE 96656dd21.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 10:59:57 -05:00

55 lines
2.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
# Row 112 (#1606): mutants on the decision.raise choice checks in broker.mjs.
# m1 restores the old shared line, so a recommendation miss refuses
# invalid-options again (the brief's required mutant).
# m2 checks the recommendation before duplicate keys, so a bad option list
# with a missing recommendation reports invalid-recommendation.
# Each runs the FULL bus suite (node --test tests/*.test.mjs in packages/bus)
# and restores broker.mjs from the .orig copy whatever happens.
# Usage: mutants.py <worktree> <log dir>
import os, shutil, subprocess, sys, signal
WT, LOGS = sys.argv[1], sys.argv[2]
SRC = os.path.join(WT, 'packages/bus/src/broker.mjs')
CUR = (" if (new Set(choices).size !== choices.length) fail('invalid-options');\n"
" if (!choices.includes(a.recommendation)) fail('invalid-recommendation');\n")
MUTANTS = {
'm1': (" if (new Set(choices).size !== choices.length || !choices.includes(a.recommendation))\n"
" fail('invalid-options');\n"),
'm2': (" if (!choices.includes(a.recommendation)) fail('invalid-recommendation');\n"
" if (new Set(choices).size !== choices.length) fail('invalid-options');\n"),
}
os.makedirs(LOGS, exist_ok=True)
text = open(SRC).read()
if text.count(CUR) != 1:
sys.exit('STOP the choice checks in broker.mjs are not unique or have moved')
if os.path.exists(SRC + '.orig'):
sys.exit('STOP broker.mjs.orig already exists')
env = dict(os.environ, TMPDIR=os.path.expanduser('~/darkwing-scratch/r112/tmp'))
for name, new in MUTANTS.items():
log_path = os.path.join(LOGS, f'mutant-{name}.log')
shutil.copy2(SRC, SRC + '.orig')
try:
open(SRC, 'w').write(text.replace(CUR, new))
with open(log_path, 'w') as out:
p = subprocess.Popen('node --test tests/*.test.mjs', shell=True, cwd=os.path.join(WT, 'packages/bus'),
stdout=out, stderr=subprocess.STDOUT, env=env, start_new_session=True)
try:
rc = p.wait(timeout=600)
except subprocess.TimeoutExpired:
os.killpg(p.pid, signal.SIGKILL)
p.wait()
rc = 'timeout'
finally:
shutil.move(SRC + '.orig', SRC)
restored = open(SRC).read() == text
log = open(log_path).read()
counts = [l for l in log.splitlines() if l.startswith(('ℹ pass', 'ℹ fail', 'ℹ skipped'))]
failed = [l.strip() for l in log.splitlines() if l.lstrip().startswith('✖') and 'failing tests' not in l]
print(f'mutant {name} rc={rc} {" ".join(counts)} restored={restored}')
for f in sorted(set(failed)):
print(' ' + f)
print('KILLED' if rc != 0 else 'SURVIVED')
if not restored:
sys.exit('STOP broker.mjs was not restored')