tooling: verified backup, state snapshot, retargetable apply validator
Promotion prep for the contract-apply cutover, which unlike the quick-sell promotion moves BOTH binaries and applies a schema migration. fifa17-promotion-backup.py uses SQLite's online backup API, not cp. Production runs WAL with a routinely uncheckpointed WAL (515 KB at capture time); copying the main file alone is not atomic against a live writer and carries no guarantee the WAL holds no newer committed state. Emits a checksummed backup, a metadata record and a RESTORE-*.sh that removes the stale -wal/-shm BEFORE restoring -- omit that and SQLite replays the old journal over the file you just put back, resurrecting the state you were abandoning. fifa17-promotion-snapshot.py is read-only (mode=ro) and counts EVERY table rather than a hand-picked list, so a delta cannot hide in a table nobody thought to name. It also fingerprints the ownership rows, catching a row silently rewritten when counts alone would match. fifa17-contract-apply-validate.py gains --host/--db so one tool serves staging, the migration rehearsal and the production acceptance run. Defaults stay staging: there is deliberately no production default, so a bare invocation cannot touch production.
This commit is contained in:
@@ -11,7 +11,9 @@ Exercises the real route end to end and asserts the full observable contract:
|
||||
* replaying the exhausted resource fails closed rather than granting again;
|
||||
* a manager contract and a non-contract consumable both fail closed.
|
||||
|
||||
Read-only against production by construction: every URL is the staging port.
|
||||
Defaults target STAGING. `--host`/`--db` retarget it at a rehearsal or, under
|
||||
explicit authorization, at the production acceptance run. There is deliberately
|
||||
no production default: a bare invocation cannot touch production.
|
||||
"""
|
||||
import argparse
|
||||
import json
|
||||
@@ -20,6 +22,9 @@ import sys
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
|
||||
# Defaults are STAGING. Override for a rehearsal or the production acceptance
|
||||
# run; there is deliberately no production default, so a bare invocation can
|
||||
# never touch production by accident.
|
||||
HOST = "http://127.0.0.1:8299"
|
||||
CORE_DB = "/home/alex/openfut-sold-staging/staging-core.db"
|
||||
HDRS = {"X-OpenFUT-Game": "fifa17"}
|
||||
@@ -123,7 +128,13 @@ def main():
|
||||
help="contract resource id to apply (default: first owned player contract)")
|
||||
ap.add_argument("--target", type=int, default=None,
|
||||
help="target player wire id (default: lowest-rated owned player)")
|
||||
ap.add_argument("--host", default=HOST, help=f"utas-host base URL (default {HOST})")
|
||||
ap.add_argument("--db", default=CORE_DB, help=f"Core SQLite path (default {CORE_DB})")
|
||||
args = ap.parse_args()
|
||||
# Rebound before any request so every helper below reads the chosen target.
|
||||
globals()["HOST"] = args.host
|
||||
globals()["CORE_DB"] = args.db
|
||||
print(f"target host : {HOST}\ntarget db : {CORE_DB}\n")
|
||||
|
||||
print("== BEFORE ==")
|
||||
before = core_snapshot()
|
||||
|
||||
Reference in New Issue
Block a user