38 lines
2.5 KiB
Python
38 lines
2.5 KiB
Python
# mutate.py <id>: apply one named mutant (each edit exact text, must match once). Run from the tree root.
|
|
import sys
|
|
CT = "packages/conversation/src/controller.mjs"
|
|
PROOF = " if (b.state !== \"stopped\" || b.admission !== \"closed\" || !this.#stopped(s)) return refused(\"stop-proof\");\n"
|
|
RECREL = " await this.#releaseListed(\"recover\", this.claim);\n"
|
|
CONF = " if (!this.#checkConfirmation(r, c, \"recover\")) return refused(\"confirmation\");\n"
|
|
KILL = " const kill = killEngine && this.b?.state !== \"stopped\";\n"
|
|
M = {
|
|
# Dewey's, spot-checked.
|
|
"norecover": [(CT, PROOF + RECREL, PROOF)],
|
|
"nostartfree": [(CT, " for (const h of [prior, seatHead]) {\n", " for (const h of []) {\n")],
|
|
"nostartstopped": [(CT, " await this.#releaseListed(\"start\", { claimId: classified.claimId, record: classified.record });\n", "")],
|
|
"closekill": [(CT, KILL, " const kill = killEngine;\n")],
|
|
"nopush": [(CT, " this.#push({ kind: \"evidence\", evidence: entry });\n", "")],
|
|
# The recover release moves after the confirmation check (the packet's K6 reading).
|
|
"recafter": [(CT, PROOF + RECREL, PROOF), (CT, CONF, CONF + RECREL)],
|
|
# The recover release moves before the stop-proof check.
|
|
"recbefore": [(CT, PROOF + RECREL, RECREL + PROOF)],
|
|
# The free path checks only the session head.
|
|
"noseat": [(CT, " for (const h of [prior, seatHead]) {\n", " for (const h of [prior]) {\n")],
|
|
# The free path drops the same-claim skip for the seat head.
|
|
"nodedupe": [(CT, " || (h === seatHead && prior.n > 0 && !prior.damaged && h.record.claimId === prior.record.claimId)) continue;", ") continue;")],
|
|
# #releaseListed sends a request even when the unit reads absent.
|
|
"nolookup": [(CT, " if ((await this.units.lookup(claim.record)).state === \"absent\") return null;\n", "")],
|
|
# #releaseListed never drops an earlier result, so #releaseScope returns it.
|
|
"nodelete": [(CT, " if (this.scopeReleases.get(claim.claimId) === earlier) this.scopeReleases.delete(claim.claimId);\n", "")],
|
|
# close skips the signal only while #stopped() still accepts the stop.
|
|
"closeproof": [(CT, KILL, " const kill = killEngine && !(this.b?.state === \"stopped\" && this.#stopped(this.stops.get(this.b.stop)));\n")],
|
|
}
|
|
if "--files" in sys.argv:
|
|
print(" ".join(sorted({f for f, _, _ in M[sys.argv[1]]}))); sys.exit(0)
|
|
for f, old, new in M[sys.argv[1]]:
|
|
s = open(f).read()
|
|
n = s.count(old)
|
|
if n != 1: sys.exit(f"{sys.argv[1]}: {n} matches in {f}")
|
|
open(f, "w").write(s.replace(old, new))
|
|
print(f)
|