Files
jason.woltjeandClaude Sonnet 5.5 df5bbfb82a researcher: row 142 round 1 packet, mosaic talk prints only the reply to its own message (#1636)
Candidate on 8e2c5c2d0: 4 files, tree 91503e62b8.
6 of 6 mutants killed, 3 controls pass, cli suite and every scripts/test-*.sh green.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-15 17:44:23 -05:00

54 lines
3.3 KiB
Bash
Executable File
Raw Permalink 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 142 (#1636): mosaic talk prints only the reply to its own message.
# Each check must fail on a mutant. For each mutant this runs one named test file against the
# real source (control) and against the source with one exact-once text edit, in the given worktree,
# one test file at a time, and restores every source file on exit.
# Usage: mutants.sh <worktree> <outdir> (MUTANT_DRY=1 only proves every edit matches exactly once)
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
if [ -n "${MUTANT_DRY:-}" ]; then echo "$1: edit ok (dry)"; return; fi
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; }
diff -u "$BAK/$3" "$3" > "$OUT/$1.patch"
run "$1" "$2"
cp "$BAK/$3" "$3"
}
C=packages/cli/src/cli.mjs; VT=packages/cli/tests/verbs.test.mjs; FT=packages/cli/tests/follow.test.mjs; TT=packages/cli/tests/tester.test.mjs
for t in "$VT" "$FT" "$TT"; do run "control-$(basename "$t" .test.mjs)" "$t"; done
# m1: no filter, so talk prints and reads everything again
mutant m1-filter-removed "$VT" "$C" ' if (!follow && m.in_reply_to !== sent.id) continue;
' ''
# m2: the filter also applies under --follow and follow, which must keep receiving everything
mutant m2-filter-under-follow "$FT" "$C" 'if (!follow && m.in_reply_to !== sent.id) continue;' 'if (m.in_reply_to !== sent?.id) continue;'
# m3: the filter is inverted, so only the other messages are printed
mutant m3-filter-inverted "$VT" "$C" 'if (!follow && m.in_reply_to !== sent.id) continue;' 'if (!follow && m.in_reply_to === sent.id) continue;'
# m4: only the reply is printed, but every message is marked read
mutant m4-read-all "$VT" "$C" ' if (!follow && m.in_reply_to !== sent.id) continue;
io.stdout.write(formatMessage(m));' ' if (follow || m.in_reply_to === sent.id) io.stdout.write(formatMessage(m));'
# m5: the timeout message goes back to claiming the next talk shows a late reply
mutant m5-timeout-message "$VT" "$C" 'it may still come, and mosaic inbox shows it' 'it may still come, and the next mosaic talk shows it'
# m6: any reply is printed, not just the reply to this message, so a late reply to an earlier one shows up
mutant m6-any-reply "$VT" "$C" 'if (!follow && m.in_reply_to !== sent.id) continue;' 'if (!follow && !m.in_reply_to) continue;'
echo "mutants finished"