Files
stack/agents/researcher/work/queue-109/mutants.sh
T
jason.woltjeandClaude Sonnet 5.5 8ea93f556e docs: Researcher row 109 candidate packet (#1603, PM reads current launch state and task status before it plans)
Candidate patch (state verb, runner state block, header time, pm.md rule, fake-adapter fixture), six new harness tests, six mutants, full suite outputs, candidate manifest.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-13 18:10:24 -05:00

51 lines
2.7 KiB
Bash
Executable File
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 bash
# Row 109 (#1603): each new check must fail on a mutant. For each mutant this runs the named test
# file against the real source (control) and against the source with one exact-once text edit.
# Runs in the given worktree, one test file at a time, and restores every source file on exit.
# Usage: mutants.sh <worktree> <outdir>
set -u
WT=$(cd "$1" && pwd); OUT=$(mkdir -p "$2" && cd "$2" && pwd)
cd "$WT" || exit 2
BAK=$(mktemp -d "$OUT/.bak.XXXXXX")
declare -A SAVED
save() { [ -n "${SAVED[$1]:-}" ] || { mkdir -p "$BAK/$(dirname "$1")"; cp "$1" "$BAK/$1"; SAVED[$1]=1; }; }
restore() { for f in "${!SAVED[@]}"; do cp "$BAK/$f" "$f"; done; rm -rf "$BAK"; }
trap restore EXIT
edit() { # file old new: exact-once replace
save "$1"
node -e '
const fs = require("fs"); const [f, a, b] = process.argv.slice(1);
const s = fs.readFileSync(f, "utf8"); const n = s.split(a).length - 1;
if (n !== 1) { console.error("expected one match, found " + n); process.exit(3); }
fs.writeFileSync(f, s.replace(a, () => b));
' "$1" "$2" "$3"
}
run() { # name testfile
setsid -w timeout -k 10 240 node --test "$2" > "$OUT/$1.out" 2>&1; echo "$?" > "$OUT/$1.rc"
echo "$1: exit $(cat "$OUT/$1.rc"); $(grep -E '^ℹ (tests|pass|fail)' "$OUT/$1.out" | tr '\n' ' ')"
grep -E '^✖' "$OUT/$1.out" | sort -u | sed 's/ ([0-9.]*ms)$//' | sed "s/^/ failed: /"
}
mutant() { # name testfile file old new
edit "$3" "$4" "$5" || { echo "$1: edit failed"; return; }
git diff -- "$3" > "$OUT/$1.patch"
run "$1" "$2"
cp "$BAK/$3" "$3"
}
R=packages/harness/src/runner.mjs; RT=packages/harness/tests/runner.test.mjs
B=packages/bus/src/broker.mjs; BT=packages/bus/tests/state.test.mjs
run control-runner "$RT"
run control-bus "$BT"
# m1: the turn request no longer carries the state block
mutant m1-drop-block "$RT" "$R" 'request: `${block}\n${turnRequest(m)}`' 'request: turnRequest(m)'
# m2: the header no longer carries the message time
mutant m2-drop-time "$RT" "$R" ' if (m.at) head.push(`sent ${m.at}`);
' ''
# m3: a failed state read no longer fails the turn; the turn runs with no block
mutant m3-drop-failure-check "$RT" "$R" 'unread = `could not read the current state: ${e.code ?? e.message}`;' 'block = "";'
# m4: the block's launch line shows the older event instead of the latest
mutant m4-oldest-launch-event "$BT" "$B" "kind IN ('launch.revoked','launch.restored') ORDER BY seq DESC LIMIT 1" "kind IN ('launch.revoked','launch.restored') ORDER BY seq ASC LIMIT 1"
# m5: the open list includes closed tasks
mutant m5-closed-in-open "$BT" "$B" 'const open = this.#tasks(s.business, { done: false });' 'const open = this.#tasks(s.business, { limit: TASK_PAGE });'
# m6: the cap isn't stated in the output
mutant m6-cap-unstated "$BT" "$B" 'total: open.total, cap: TASK_PAGE }' 'total: open.total }'