Files
stack/agents/darkwing/work/queue-51-review/r1/mut/mutate.py
T

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)