Files
stack/agents/researcher/work/queue-109/mutants.sh
T

73 lines
4.0 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), round 3 adds m7-m12: the two re-anchored tests (seat session, cli launcher) and the two N2 tests.
# 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 400 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 }'
# Round 3. SE and CL are the seat and cli tests that now anchor the new request shape.
SE=packages/seat/tests/session.test.mjs; CL=packages/cli/tests/launcher.test.mjs
run control-seat "$SE"
run control-cli "$CL"
# m7, m9: the turn request no longer carries the state block
mutant m7-seat-drop-block "$SE" "$R" 'request: `${block}\n${turnRequest(m)}`' 'request: turnRequest(m)'
mutant m9-cli-drop-block "$CL" "$R" 'request: `${block}\n${turnRequest(m)}`' 'request: turnRequest(m)'
# m8, m10: the header no longer carries the message time
mutant m8-seat-drop-time "$SE" "$R" ' if (m.at) head.push(`sent ${m.at}`);
' ''
mutant m10-cli-drop-time "$CL" "$R" ' if (m.at) head.push(`sent ${m.at}`);
' ''
# m11: a human session is checked as an agent, so it can't read state
mutant m11-human-checked-as-agent "$BT" "$B" 'if (!s.human && !s.reader) this.#agent(s);
const set' 'if (!s.reader) this.#agent(s);
const set'
# m12: the state read writes an event
mutant m12-state-writes-event "$BT" "$B" " case 'state': {
keys(a, []);" " case 'state': {
keys(a, []);
this.#event(s, 'action.allowed', {});"