textmachine/platform/docs/p8-review/plant.py

96 lines
4.9 KiB
Python
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 python3
"""P8-REVIEW: mutation harness. Plants one named mutation into the WORKING COPY, leaving the
repository untouched, and prints the file it changed. Reverting is a copy back from the repo.
Usage: plant.py <id> plant|revert
"""
import shutil, subprocess, sys, os
# Оба переопределяются: копия — там, где её положила сессия, репозиторий — источник, из которого
# делается откат. Дефолты совпадают с рецептом в README этого каталога.
REPO = os.environ.get("P8_REPO", os.path.expanduser("~/projects/textmachine/platform"))
COPY = os.environ.get("P8_COPY", os.path.expanduser("~/tm-p8-review/mine/platform"))
M = {
# id: (file, old, new, packages that must be re-run)
# --- дописано после ревью старшей моделью: улики M1/M2/M9 не были воспроизводимы из артефактов,
# --- плюс шесть пере-проверок «выживших» на ПОЛНОЙ батарее вместо пакетного сабсета.
"M1": ("internal/pgstore/credits.go",
'\t\tif unit != nil {\n\t\t\treturn fmt.Errorf("%w: %s", ErrAttemptSpawned, *unit)\n\t\t}',
'\t\t_ = unit // MUTATION M1: re-check removed',
"ALL"),
"M2": ("internal/runs/reconcile.go",
'\tif bound != nil && *bound < committed {\n\t\tcommitted = *bound\n\t}',
'\t_ = bound // MUTATION M2: SpendBound clamp removed',
"ALL"),
"M9": ("internal/metrics/metrics.go",
'\tif unfinished {\n\t\tm.sweepUnfinished.WithLabelValues(name).Inc()\n\t}\n',
'\t// MUTATION M9: an unfinished pass is not counted\n',
"ALL"),
"M11": ("internal/pgstore/runs.go",
'\t\tselect min(a.spend_baseline_micro_usd)',
'\t\tselect max(a.spend_baseline_micro_usd) -- MUTATION M11',
"ALL"),
"M12": ("internal/pgstore/sessions.go",
'now.Add(idleTTL), now.Add(maxAge))',
'now.Add(idleTTL), now.Add(100*maxAge))',
"ALL"),
"M13": ("internal/auth/cookie.go",
'func (c Cookies) ClearSession(w http.ResponseWriter) { c.set(w, c.SessionName(), "", -time.Second) }',
'func (c Cookies) ClearSession(w http.ResponseWriter) { c.set(w, c.SessionName(), "", time.Hour) } // MUTATION M13',
"ALL"),
"M14": ("internal/auth/cookie.go",
'\tif ttl < 0 {\n\t\tmaxAge = -1\n\t}',
'\tif ttl < 0 {\n\t\tmaxAge = 3600 // MUTATION M14\n\t}',
"ALL"),
"M15": ("cmd/tmplatformd/main.go",
'const loginJournalRetention = 180 * 24 * time.Hour',
'const loginJournalRetention = 180 * 365 * 24 * time.Hour // MUTATION M15',
"ALL"),
"M16": ("internal/pgstore/identity.go",
'`delete from login_events where at < $1`',
'`delete from login_events where at < $1 and 1=0`',
"ALL"),
"M3": ("internal/pgstore/credits.go",
'\tif !applied {\n\t\t// The ledger already holds this attempt id, so nothing was debited. Reporting success\n\t\t// would spawn a run against credit that was never reserved.\n\t\treturn ErrDuplicateHold\n\t}',
'\tif !applied {\n\t\treturn nil // MUTATION M3\n\t}',
"./internal/pgstore/ ./internal/runs/"),
"M4": ("internal/pgstore/credits.go",
'\tif spent < 0 {\n\t\treturn fmt.Errorf("pgstore: spend cannot be negative, got %d", spent)\n\t}\n',
'\t// MUTATION M4: negative-spend guard removed\n',
"./internal/pgstore/ ./internal/runs/"),
"M5": ("internal/runs/reconcile.go",
'\tif committed < *l.SpendBaseline {\n\t\treturn 0, nil\n\t}\n',
'\t// MUTATION M5: clamp-at-zero removed\n',
"./internal/runs/ ./internal/pgstore/"),
"M6": ("internal/auth/cookie.go",
'\t\tSecure: !c.Insecure,',
'\t\tSecure: false, // MUTATION M6',
"./internal/auth/ ./internal/login/ ./internal/httpapi/ ./cmd/tmplatformd/"),
"M7": ("internal/runs/reconcile.go",
'\treturn context.WithTimeout(ctx, time.Until(deadline)/2)',
'\treturn context.WithTimeout(ctx, time.Until(deadline)) // MUTATION M7',
"./internal/runs/ ./cmd/tmplatformd/"),
"M8": ("internal/metrics/metrics.go",
'\tm.stalledRuns.Set(float64(r.StalledRuns))\n',
'\t// MUTATION M8: the stalled gauge is never set\n',
"./internal/metrics/ ./cmd/tmplatformd/ ./internal/runs/"),
"M10": ("internal/metrics/metrics.go",
'\tm.abandonedSurfaces.Set(float64(r.AbandonedSurfaces))\n',
'\t// MUTATION M10: the abandoned-surfaces gauge is never set\n',
"ALL"),
}
mid, action = sys.argv[1], sys.argv[2]
f, old, new, pkgs = M[mid]
src, dst = os.path.join(REPO, f), os.path.join(COPY, f)
shutil.copyfile(src, dst)
if action == "revert":
print(f"{mid}: reverted {f}")
sys.exit(0)
s = open(dst).read()
if old not in s:
sys.exit(f"{mid}: ANCHOR NOT FOUND in {f}")
open(dst, "w").write(s.replace(old, new, 1))
print(f"{mid}: planted in {f}; packages to run: {pkgs}")