#!/usr/bin/env bash
# Row 93 (#1587) mutants. Run from the candidate worktree's root:
# LOG=
bash mutants.sh /path/to/mut.mjs > mutants.txt
# Each mutant edits one site with mut.mjs (exactly one match, else exit 3),
# runs the named test files and restores the file. "killed" means the run
# failed; "survived" means it passed.
set -u
MUT=$1
run() {
local name=$1 file=$2 from=$3 to=$4; shift 4
cp -- "$file" "$file.orig"
if ! node "$MUT" "$file" "$from" "$to"; then
echo "$name: NO MATCH"; mv -- "$file.orig" "$file"; return
fi
if node --test "$@" > "${LOG:-.}/mut-$name.log" 2>&1; then
echo "$name: survived"
else
echo "$name: killed ($(grep -m1 -o 'ℹ fail [0-9]*' "${LOG:-.}/mut-$name.log"), $(grep -m1 '^✖' "${LOG:-.}/mut-$name.log" | cut -c1-90))"
fi
mv -- "$file.orig" "$file"
}
WK=packages/seat/src/working.mjs
GS=packages/cli/src/git-socket.mjs
BR=packages/bus/src/broker.mjs
L=packages/cli/src/launcher.mjs
V=packages/tasks/src/verbs.mjs
WT=(packages/seat/tests/working.test.mjs)
GT=(packages/cli/tests/git-socket.test.mjs)
RT=(packages/bus/tests/review.test.mjs)
LT=(packages/cli/tests/launcher.test.mjs)
VT=(packages/tasks/tests/verbs.test.mjs)
# Decision 135 and Sage's ruling 3
run fsck-off $WK 'export const FSCK = ["-c", "transfer.fsckObjects=true"];' 'export const FSCK = [];' "${WT[@]}" "${GT[@]}"
run plus-refspec $WK '`${incoming}:${ref}`' '`+${incoming}:${ref}`' "${WT[@]}"
run ref-from-request $WK 'const ref = `refs/heads/${workRef(taskRef)}`;' 'const ref = `refs/heads/${branch}`;' "${WT[@]}" "${GT[@]}"
run cap-off-push $GS $' workRef(task_ref);\n if (size > bundleMax)' $' workRef(task_ref);\n if (false)' "${GT[@]}"
run cap-off-fetch $GS $' const size = statSync(file).size;\n if (size > bundleMax)' $' const size = statSync(file).size;\n if (false)' "${GT[@]}"
run refuse-subject-null $BR '{ args: { task_ref: subject } }' '{ args: { task_ref: null } }' "${RT[@]}" "${GT[@]}"
# Extras
run no-close-check $BR $' if (action === \'task.close\') this.#closeVerdict(s, context.target, context.verdict);\n' '' "${RT[@]}" "${VT[@]}"
run no-verdict-stale $BR $' if (body.commit !== push.commit) fail(\'verdict-stale\');\n' '' "${RT[@]}" "${VT[@]}"
run verbs-drop-verdict $V ", ...(verb === 'task.close' ? { verdict: args.verdict } : {})" '' "${VT[@]}"
run push-forgeable $BR $' if (kind === \'action.allowed\' && body?.action === \'git.push.working\') fail(\'reserved-event\');\n' '' "${RT[@]}"
run no-request-commit-check $BR 'if (push?.commit !== a.commit) {' 'if (false) {' "${RT[@]}"
run no-merge-base $WK $' if (!(await git([...at, "merge-base", commit, "refs/heads/main"], env)).ok) refuse("unrelated-history", "the commit shares no history with main");\n' '' "${WT[@]}"
run no-reseed-on-push $WK $' await ensure(repo, env);\n await seed(repo, root, env);' ' await ensure(repo, env);' "${WT[@]}"
run bundle-kept $GS 'if (file) rmSync(file, { force: true });' '' "${GT[@]}"
run git-socket-always $L 'held.includes("git.push.working") || held.includes("review.verdict") ? gitSocketPath(dataRoot) : null' 'gitSocketPath(dataRoot)' "${LT[@]}"