Files
stack/agents/researcher/work/queue-71/r1/mutants.py
T
jason.woltjeandClaude Opus 5.5 471f5cf202 researcher: row 71 round 1 packet on ac6b56ee, tasks 89/0, bus 115/0, mutants killed (#1565)
Haiku subagent build under decision 129. Candidate manifest 9ac3a56e
names packages/tasks/src/fake.mjs and packages/tasks/tests/tree.test.mjs.
Gate and both named mutants ran in Sage's slot.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 09:50:00 -05:00

96 lines
3.5 KiB
Python

#!/usr/bin/env python3
"""Row 71 round 1 mutants, run from the worktree root after gate.sh passes.
Each mutant is one edit to packages/tasks/src/sync.mjs, applied alone, followed by
the tasks suite. The original bytes are held in memory and written back in a
finally block, and the sha256 is checked after the last restore.
A mutant is killed when the suite exits nonzero. A 124 exit is a timeout and is
reported as such, not as a kill.
"""
import datetime
import hashlib
import os
import re
import subprocess
import sys
SYNC = 'packages/tasks/src/sync.mjs'
P = 'agents/researcher/work/queue-71/r1'
OUT = P + '/out'
ORIG_SHA = '35e79dc2ac56af8047bef11a5aaf5f1d37ce3e11513f9968454053068f59ebcf'
LINE = ' return r.status === 403 || r.status === 404;'
MUTANTS = [
# Filbert N3: the confirm read treats any 4xx as "left".
('r3-confirm-4xx', LINE, ' return r.status >= 400 && r.status < 500;'),
# Dewey: the confirm read's failed call (status 0) counts as "left".
('r3-confirm-error-on-throw', LINE, ' return r.status === 403 || r.status === 404 || r.status === 0;'),
]
def stamp():
return datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ')
def sha(path):
with open(path, 'rb') as f:
return hashlib.sha256(f.read()).hexdigest()
def write(path, data):
with open(path, 'wb') as f:
f.write(data)
def run_suite(name):
log = f'{OUT}/mutant-{name}.log'
cmd = ['env', 'DOCKER_HOST=unix:///nonexistent.sock', 'node', '--test', '--test-reporter=tap', 'packages/tasks/tests/*.test.mjs']
rc = subprocess.run(['python3', P + '/run_group.py', '900', log, os.getcwd(), '--'] + cmd).returncode
with open(log, encoding='utf-8', errors='replace') as f:
text = f.read()
failing = []
for m in re.finditer(r'^\s*not ok \d+ - (.+)$', text, re.M):
name_ = m.group(1).strip()
if name_ not in failing:
failing.append(name_)
counts = ' '.join(re.findall(r'^# (?:tests|pass|fail) \d+', text, re.M))
return rc, failing, counts
def main():
if not os.path.isfile(SYNC):
sys.exit('run from the worktree root')
os.makedirs(OUT, exist_ok=True)
original = open(SYNC, 'rb').read()
if hashlib.sha256(original).hexdigest() != ORIG_SHA:
sys.exit('sync.mjs is not the candidate copy; refusing to mutate it')
text = original.decode('utf-8')
summary = []
try:
for name, old, new in MUTANTS:
if text.count(old + '\n') != 1:
sys.exit(f'{name}: target line must occur exactly once')
mutated = text.replace(old + '\n', new + '\n').encode('utf-8')
write(SYNC, mutated)
t0 = stamp()
rc, failing, counts = run_suite(name)
t1 = stamp()
write(SYNC, original)
if sha(SYNC) != ORIG_SHA:
sys.exit(f'{name}: restore did not reproduce the original sha256')
status = 'killed' if rc not in (0, 124) else ('timeout' if rc == 124 else 'SURVIVED')
summary.append(f'{name} {status} rc={rc} start={t0} end={t1} {counts}')
for n in failing:
summary.append(f' not ok: {n}')
finally:
write(SYNC, original)
final = sha(SYNC)
summary.append(f'restored {SYNC} sha256 {final} {"OK" if final == ORIG_SHA else "MISMATCH"}')
with open(OUT + '/mutants-summary.txt', 'w', encoding='utf-8') as f:
f.write('\n'.join(summary) + '\n')
print('\n'.join(summary))
sys.exit(0 if final == ORIG_SHA else 1)
if __name__ == '__main__':
main()