Files
felhom.eu/documentation/audits/night-2026-09-23/chaos_schedule.py
T
admin 0030cbd1de
gates / gates (push) Successful in 26s
night 2026-09-23: evidence so far (Parts A, B, C in progress)
The records the catalog's ladder entries cite (apps/<app>/bench and
apps/<app>/verdict.json), the drill tools, the spike, R-626's run,
R-612/R-613 red-proofs, the chaos schedule (seed 20260923) drawn
BEFORE round 1. Docs and register follow at the end of the night.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-23 21:33:54 +02:00

61 lines
2.8 KiB
Python

#!/usr/bin/env python3
"""chaos_schedule.py — Part D's twelve rounds, drawn ONCE from seed 20260923 and committed before round 1.
python3 chaos_schedule.py # prints the table the findings doc carries
Each round is ACTION x ACCIDENT, the accident landing DELAY seconds into the action.
actions : good_update · fail_health (wrong probe -> the undo) · cutoff (the undo's copy loses its
finished-marker -> an honest HOLD) · install · remove · restore
accidents : none · power_cut (pct stop/start) · controller_kill (kill -9, max 3, >= 20 min apart)
· docker_restart · disk_fill (to 1 GB above the update floor) · memory_hog (1 GB, 5 min)
· box_backup (the whole-box backup, on 9202 only) · two_updates (a second Update pressed
at the same moment)
The draw is constrained, and the constraints are the brief's, not tuning: rounds 1 and 12 are `none`;
every action appears twice; every accident appears at least once; `controller_kill` at most three
times and never in consecutive-or-adjacent rounds (a round lasts ~6-8 min, so two rounds between
kills keeps them >= 20 min apart). A draw that breaks a constraint is redrawn from the SAME generator,
so the schedule is a pure function of the seed.
WHICH APP a round acts on is NOT drawn: it is fixed by rule in chaos.py (the action decides the app
class) and printed beside the schedule, because an app's state after round N decides what round N+1
can do to it.
"""
import random
SEED = 20260923
ACTIONS = ["good_update", "fail_health", "cutoff", "install", "remove", "restore"]
ACCIDENTS = ["power_cut", "controller_kill", "docker_restart", "disk_fill", "memory_hog",
"box_backup", "two_updates"]
def draw():
rng = random.Random(SEED)
tries = 0
while True:
tries += 1
acts = ACTIONS * 2
rng.shuffle(acts)
mid = ACCIDENTS + [rng.choice(ACCIDENTS) for _ in range(3)]
rng.shuffle(mid)
accs = ["none"] + mid + ["none"]
kills = [i for i, a in enumerate(accs) if a == "controller_kill"]
if len(kills) > 3 or any(b - a < 3 for a, b in zip(kills, kills[1:])):
continue
# an install/remove round cannot also be `two_updates` (there is no second update to race)
if any(a in ("install", "remove") and c == "two_updates" for a, c in zip(acts, accs)):
continue
delays = [rng.randint(10, 60) for _ in range(12)]
return [{"round": i + 1, "action": acts[i], "accident": accs[i], "delay_s": delays[i]}
for i in range(12)], tries
if __name__ == "__main__":
rounds, tries = draw()
print(f"seed {SEED}, drawn in {tries} attempt(s)\n")
print("| round | action | accident | at +s |")
print("|---|---|---|---|")
for r in rounds:
print(f"| {r['round']} | {r['action']} | {r['accident']} | {r['delay_s']} |")