Files
felhom.eu/documentation/audits/the-28-2026-09-22/mkrotation.py
T
admin 186546d562
gates / gates (push) Successful in 27s
THE TWENTY-EIGHT: every app no drill had touched, walked in one night
All 28 walked on scratch guest 9202 against the private drill catalog. 26 deployed, 6 proven,
5 inconclusive, 14 with no upstream edge, 1 failed honestly (outline 1.9.1->1.10.1, HELD with the
right sentence), 2 undeployable - one (plant-it) by design, refused by the lifecycle gate, proven
live for the first time. Each app also got the half the update night skipped: a restore from its own
copy with the seed read back again - 21 restored, 2 correctly REFUSED per 07 6.2.

R-630 RAISED TO P1 by measurement: a stack with NO probe container does not skip verifying - it
waits out the full health timeout and HOLDS, stopping an app whose three containers read healthy.
The controller's own words: "not healthy within 5m0s (last: no probe container)".

R-633 opened: a remove sent during a restore reports success and leaves a container restarting with
a live public route. The product already refuses that clash for update and for restore, naming the
blocker; remove has no such guard.

R-634 opened: an app can be running, healthy and serving while recorded as deployed=false, and is
then unremovable. Reproducible alone on sparkyfitness; concurrency-linked on two others.

R-631 and R-632 CLOSED. Register 321 -> 323. Seven interventions, six of them my own harness -
named, with what each cost. No product code. The live catalog's image: lines are byte-identical to
the start of the night.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-22 16:00:56 +02:00

63 lines
2.7 KiB
Python

#!/usr/bin/env python3
"""Rewrite the rotation file's line for each of the 28, from its own verdict record.
A tick means the app was WALKED FULLY — deployed, backed up, restored, removed clean. An app whose
data half is `inconclusive` is still ticked when the rest of the walk completed, and the line SAYS
what could not be judged; an app that could not be deployed is not ticked.
"""
import glob, io, json, os, re
HERE = os.path.dirname(os.path.abspath(__file__))
ROT = "/mnt/5_hdd/felhom.eu/git/felhom.eu/documentation/runbooks/nightly-rotation.md"
D = "2026-09-22"
EV = "`audits/DRILL-the-28-2026-09-22.md`"
recs = {}
for f in glob.glob(os.path.join(HERE, "apps", "*", "verdict.json")):
d = json.load(open(f, encoding="utf-8"))
recs[d["app"]] = d
def line(a, d):
if not d["deployed"]:
why = "; ".join(d["notes"]) or "deploy refused"
return (f"- [ ] {a} — NOT A FULL WALK; attempted {D} (the 28, scratch guest 9202): "
f"**could not be deployed** — {why}. {EV}.")
bits = ["install", f"front door {d.get('front_door_after_deploy',{}).get('code','?')}"]
if d["seed_read_before"]:
bits.append(f"seeded through {d.get('seed_route')} and read back")
else:
bits.append("NO non-browser data route (" + (
"; ".join(n for n in d["notes"] if "route" in n) or "recorded, not faked") + ")")
bits.append("„Mentés most\"")
e = d.get("edge")
if e:
bits.append("real upstream Update %s->%s (%s)" % (
e["from"].rsplit(":", 1)[1], e["to"].rsplit(":", 1)[1],
d.get("update_phase_final")))
if d.get("migration_observed"):
bits.append("own migration line quoted")
if d["seed_read_after_update"]:
bits.append("read back after the update")
else:
bits.append("no upstream edge tonight")
bits.append("restore " + str(d.get("restore_verdict")))
if d["seed_read_after_restore"]:
bits.append("read back after the restore")
bits.append("removed " + ("clean" if d.get("removed_clean") else "**with a leftover container**"))
tick = "x" if (d["deployed"] and d.get("removed_clean")) else " "
pre = "" if tick == "x" else "NOT A FULL WALK; attempted "
return f"- [{tick}] {a} — {pre}{D} (the 28, scratch guest 9202): " + ", ".join(bits) + f". {EV}."
t = io.open(ROT, encoding="utf-8").read()
n = 0
for a, d in sorted(recs.items()):
pat = re.compile(r'^- \[[ x]\] ' + re.escape(a) + r'( .*)?$', re.M)
if pat.search(t):
t = pat.sub(lambda m: line(a, d).replace("\\", "\\\\"), t, count=1)
n += 1
else:
print(" NO EXISTING LINE for", a)
io.open(ROT, "w", encoding="utf-8").write(t)
print(f"rewrote {n} rotation lines")