54 lines
3.9 KiB
Python
54 lines
3.9 KiB
Python
#!/usr/bin/env python3
|
|
# Row 292 mutants. M1-M5 are Gander's (agents/gander/work/config-checks-any-key/changes.json), with
|
|
# the same edits on the resolved config_checks; M1 restores the console-only skip (the brief's
|
|
# required mutant). M6-M9 are the resolution's: row 203's console and federation text. `apply <id>`
|
|
# edits the worktree and prints the touched path; each edit asserts its anchor appears exactly once.
|
|
# `check` prints each anchor's count and kill. K is read from the tests, not run. A restore is `git checkout -- <path>`, then sha256 against the blob in BUILD.md.
|
|
import sys
|
|
WT = "/mnt/storage/scratch/gizmo-292/"
|
|
S = "scripts/stack-release.sh"
|
|
T = "packages/cli/tests/stack-release.test.mjs"
|
|
M = {
|
|
"M1": (S, ' [ "$key" != 1 ] || return 0\n if [ "$key" != 0 ]; then',
|
|
' [ "$key" != 1 ] || return 0\n [ "$extra" = \'"console"\' ] || return 0\n if [ "$key" != 0 ]; then'),
|
|
"M2": (S, 'elif out="$(MOSAIC_CONFIG="$cfg" node "$loader" validate 2>&1 >/dev/null)"; then return 0',
|
|
'elif out="$(MOSAIC_CONFIG="$cfg" node "$loader" validate 2>&1 >/dev/null)" || true; then return 0'),
|
|
"M3": (S, ' [ -n "$extra" ] || return 0', ' return 0 # drop missing-loader later-key refusal'),
|
|
"M4": (S, ' if [ "$key" != 0 ]; then\n check_refuse config-console-key',
|
|
' if [ "$key" = 99 ]; then\n check_refuse config-console-key'),
|
|
"M5": (S, ' if [ ! -f "$loader" ]; then', ' [ -n "$extra" ] || return 0\n if [ ! -f "$loader" ]; then'),
|
|
"M6": (S, 'Object.hasOwn(d,"federation")?"federation":', ''),
|
|
"M7": (S, 'const k=Object.hasOwn(d,"console")?"console":', 'const k='),
|
|
"M8": (S, ' if [ "$extra" = \'"console"\' ] || [ "$extra" = \'"federation"\' ]; then\n check_refuse',
|
|
' if [ "$extra" = \'"console"\' ]; then\n check_refuse'),
|
|
"M9": (S, '[ "$extra" = \'"federation"\' ]; then out="it has no scripts/mosaic-config.mjs"',
|
|
'[ "$extra" = \'"federation-off"\' ]; then out="it has no scripts/mosaic-config.mjs"'),
|
|
}
|
|
# K: (--test-name-pattern, the test.mjs lines the failing stack must show, the text the failure
|
|
# must show). Kill rule (sage-3152): the named test fails, its first error's stack names every
|
|
# listed line, and the log holds the text (no quote characters, which node's inspect may escape). A fail anywhere else, or a crash first, is a STOP to Sage.
|
|
# A survivor of its targeted run gets one whole-file run before it counts as a survivor.
|
|
K = {
|
|
"M1": ('^config-any-key: a non-console target refusal stops activate and rollback before any stop$', [517, 2619], "actual: 0"),
|
|
"M2": ('^config-any-key: a non-console target refusal stops activate and rollback before any stop$', [517, 2619], "actual: 0"),
|
|
"M3": ('^config-any-key: missing-loader copies accept only the four oldest keys$', [2670], "actual: 0"),
|
|
"M4": ('^config-any-key: missing config passes but malformed JSON refuses without calling the loader$', [2684], "actual: 0"),
|
|
"M5": ('^config-any-key: accepting loaders run validate with the selected config on activate and rollback$', [2654], "actual: []"),
|
|
"M6": ('^config-any-key: missing-loader copies accept only the four oldest keys$', [2677], "to validate configuration key: "),
|
|
"M7": ('^config-any-key: missing-loader copies accept only the four oldest keys$', [2677], "to validate configuration key: "),
|
|
"M8": ('^config-any-key: missing-loader copies accept only the four oldest keys$', [2677], "is refused by old"),
|
|
"M9": ('^config-any-key: missing-loader copies accept only the four oldest keys$', [2677], "to validate configuration key: "),
|
|
}
|
|
cmd = sys.argv[1]
|
|
if cmd == "list":
|
|
print(" ".join(M)); sys.exit(0)
|
|
if cmd == "check":
|
|
for k, (f, a, b) in M.items():
|
|
print(k, f, open(WT + f).read().count(a), "kill:", *K[k])
|
|
sys.exit(0)
|
|
f, a, b = M[sys.argv[2]]
|
|
s = open(WT + f).read()
|
|
assert s.count(a) == 1, (sys.argv[2], s.count(a))
|
|
open(WT + f, "w").write(s.replace(a, b))
|
|
print(f)
|