#!/usr/bin/env python3 """Part E's schedule — night 2026-09-24. Deterministic: seed 20260924, 12 rounds of action x accident. Committed BEFORE round 1 and printed into DRILL-night-2026-09-24.md, so the schedule cannot be chosen after the fact. Constraints from the brief: every action at least once; controller killed at most 3 times, at least 20 minutes apart (rounds are ~6 min, so kills sit >= 4 rounds apart); a whole-box backup only on 9202. python3 chaos_schedule.py # prints the table python3 chaos_schedule.py --json # for the runner """ import json import random import sys SEED = 20260924 ROUNDS = 12 ROUND_MIN = 6 # planned length of one round, minutes ACTIONS = [ "ladder_step", # a proven ladder step (Update) "failing_step", # a step whose probe fails -> undo "cutoff_undo_file_app", # a file app's undo copy cut off -> the second-drive whole restore "crash_loop", # a drill image that exits -> the box stops it "oom_app", # a tiny mem_limit -> out-of-memory kills "install", "remove_held", # Remove on a held app "start_after_unhealthy",# Start after the box stopped an app ] ACCIDENTS = ["none", "power_cut", "controller_killed", "docker_restart", "disk_to_floor_plus_1g", "whole_box_backup"] MAX_KILLS, KILL_GAP_MIN = 3, 20 def schedule(seed=SEED): rng = random.Random(seed) for _ in range(10000): acts = ACTIONS + [rng.choice(ACTIONS) for _ in range(ROUNDS - len(ACTIONS))] rng.shuffle(acts) accs = [rng.choice(ACCIDENTS) for _ in range(ROUNDS)] kills = [i for i, a in enumerate(accs) if a == "controller_killed"] if len(kills) > MAX_KILLS: continue if any((b - a) * ROUND_MIN < KILL_GAP_MIN for a, b in zip(kills, kills[1:])): continue # Start-after-unhealthy needs an app the box stopped: never before the first crash_loop/oom_app. first_stop = min(i for i, a in enumerate(acts) if a in ("crash_loop", "oom_app")) if acts.index("start_after_unhealthy") < first_stop: continue # Remove-on-held needs a held app: after a failing_step or cutoff. first_hold = min(i for i, a in enumerate(acts) if a in ("failing_step", "cutoff_undo_file_app")) if acts.index("remove_held") < first_hold: continue return [{"round": i + 1, "action": acts[i], "accident": accs[i]} for i in range(ROUNDS)] raise SystemExit("no schedule satisfies the constraints") if __name__ == "__main__": s = schedule() if "--json" in sys.argv: print(json.dumps(s, indent=1)) else: print(f"seed {SEED}, {ROUNDS} rounds") print("| round | action | accident |\n|---|---|---|") for r in s: print(f"| {r['round']} | {r['action']} | {r['accident']} |")