Files
stack/agents/darkwing/work/queue-104/r1/mutants.py
T
jason.woltjeandClaude Opus 5.5 b2ae135524 docs: Darkwing row 104 round 1 packet, seats commit under their own name (#1598)
Candidate against 817ddfea6: git identity in the sandbox environment,
commit field in checkout results, one prompt line. Gate green, 19 of 19
mutants killed. The candidate itself is not committed.

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

104 lines
5.8 KiB
Python

#!/usr/bin/env python3
# Row 104 (#1598) mutants. Each takes out or bends one new check; the named
# test files must fail on it. Each file is restored from its .orig after the
# run, and the candidate's diff must hash the same at the end as at the start.
import hashlib, os, signal, subprocess, sys, time
WT = os.path.expanduser("~/darkwing-scratch/r104/wt")
OUT = os.path.expanduser("~/darkwing-scratch/r104/mutants")
ENV = dict(os.environ, TMPDIR=os.path.expanduser("~/darkwing-scratch/r104/tmp"))
os.makedirs(OUT, exist_ok=True)
os.makedirs(ENV["TMPDIR"], exist_ok=True)
SB, CO, BU, SE, LA = (
"packages/seat/src/sandbox.mjs", "packages/seat/src/checkout.mjs", "packages/harness/src/bundle.mjs",
"packages/seat/src/session.mjs", "packages/cli/src/launcher.mjs")
T_SB, T_CO, T_BU, T_SE, T_LA = (
"packages/seat/tests/sandbox.test.mjs", "packages/seat/tests/checkout.test.mjs", "packages/harness/tests/bundle.test.mjs",
"packages/seat/tests/session.test.mjs", "packages/cli/tests/launcher.test.mjs")
M = [
("m01 sandboxArgv drops the identity setenv", SB,
'"/tmp", ...identity, "--chdir"', '"/tmp", "--chdir"', [T_SB, T_LA]),
("m02 gitIdentity checks nothing", SB,
'if (typeof id !== "string" || !ID_PATTERN.test(id)) throw', 'if (false) throw', [T_SB]),
("m03 gitIdentity checks the type only", SB,
'typeof id !== "string" || !ID_PATTERN.test(id)', 'typeof id !== "string"', [T_SB]),
("m04 the email drops the business", SB,
'`${role}@${business}.mosaic.invalid`', '`${role}@mosaic.invalid`', [T_SB, T_LA]),
("m05 clone() returns no commit", CO,
'return { outcome: "cloned", branch: at.branch, commit };', 'return { outcome: "cloned", branch: at.branch };', [T_CO]),
("m06 clone() skips the HEAD check", CO,
'if (!head.ok) throw new CheckoutError(project, `the new clone', 'if (false) throw new CheckoutError(project, `the new clone', [T_CO]),
("m07 update() returns no commit", CO,
'branch: at.branch, commit: read.ok ? after : null }', 'branch: at.branch }', [T_CO]),
("m08 update() has no null fallback", CO,
'commit: read.ok ? after : null }', 'commit: after }', [T_CO]),
("m09 a kept clone gets a commit field", CO,
'if (problem) return { outcome: "kept", reason: problem };', 'if (problem) return { outcome: "kept", reason: problem, commit: null };', [T_CO]),
("m10 a kept clone gets a git run", CO,
'if (problem) return { outcome: "kept", reason: problem };',
'if (problem) { await g([...inClone(dest), "rev-parse", "HEAD"]); return { outcome: "kept", reason: problem }; }', [T_CO]),
("m11 the prompt drops the commit", BU,
'(c.commit ? `commit ${c.commit}` : ', '(c.commit ? "a commit" : ', [T_BU, T_LA]),
("m12 the prompt has no unreadable-commit text", BU,
'(c.commit ? `commit ${c.commit}` : "a commit the host couldn\'t read")', '`commit ${c.commit}`', [T_BU]),
("m13 the prompt drops the branch", BU,
'on branch ${c.branch} at ${at(c)}', 'at ${at(c)}', [T_BU, T_LA]),
("m14 the prompt drops the config warning", BU,
"Don't set git config in a clone. Any key that \\`git clone\\` didn't write, user.name and user.email included, makes every later launch keep that clone as it is. ", "", [T_BU]),
("m15 the prompt drops the launch-only refresh", BU,
"The host fetches from its origin and fast-forwards a clean clone only at a launch, never during a session; the origin is outside this sandbox. ", "", [T_BU]),
("m16 spawnSession passes no identity", SE,
'{ business, role, bwrap }', '{ bwrap }', [T_SE, T_LA]),
("m17 spawnSession fixes the role", SE,
'{ business, role, bwrap }', '{ business, role: "coder", bwrap }', [T_LA]),
("m18 the launcher passes the definition role", LA,
'business: b.id, role: instance, bwrap', 'business: b.id, role: "pm", bwrap', [T_LA]),
("m19 the launcher passes another business", LA,
'business: b.id, role: instance, bwrap', 'business: "x", role: instance, bwrap', [T_LA]),
]
def diffhash():
d = subprocess.run(["git", "-C", WT, "diff", "--", ".", ":!node_modules"], capture_output=True).stdout
return hashlib.sha256(d).hexdigest()
def run(test, log):
pkg = os.path.join(WT, *test.split("/")[:2])
with open(log, "ab") as f:
f.write(f"== {test}\n".encode()); f.flush()
p = subprocess.Popen(["node", "--test", os.path.relpath(os.path.join(WT, test), pkg)], cwd=pkg, env=ENV,
stdout=f, stderr=subprocess.STDOUT, start_new_session=True)
try:
return p.wait(timeout=600)
except subprocess.TimeoutExpired:
os.killpg(p.pid, signal.SIGKILL); p.wait(); return "timeout"
for _, path, *_ in M:
if os.path.exists(os.path.join(WT, path + ".orig")):
sys.exit(f"STOP {path}.orig exists")
start = diffhash()
print(f"start diff {start[:16]} {time.strftime('%H:%M:%S', time.gmtime())}", flush=True)
bad = []
only = set(sys.argv[1:])
for name, path, old, new, tests in M:
if only and name.split()[0] not in only: continue
full = os.path.join(WT, path)
src = open(full).read()
if src.count(old) != 1:
print(f"{name}: ANCHOR {src.count(old)}", flush=True); bad.append(name); continue
os.rename(full, full + ".orig")
try:
open(full, "w").write(src.replace(old, new))
log = os.path.join(OUT, name.split()[0] + ".log")
open(log, "w").close()
rcs = [run(t, log) for t in tests]
finally:
os.replace(full + ".orig", full)
killed = all(rc not in (0, "timeout") for rc in rcs)
print(f"{name}: {'killed' if killed else 'SURVIVED'} {list(zip([t.split('/')[-1] for t in tests], rcs))}", flush=True)
if not killed: bad.append(name)
end = diffhash()
print(f"end diff {end[:16]} {'same' if end == start else 'CHANGED'} {time.strftime('%H:%M:%S', time.gmtime())}", flush=True)
print("MUTANTS_OK" if not bad and end == start else f"MUTANTS_BAD {bad}")