"""Phase 08 drivers: R1 interruption/resumption, R2 stale-input invalidation, R3 duplicate submission, R4 missing fixture. Usage: PYTHONPATH=src .venv/bin/python -m pgar.recovery_experiment r1|r2|r3|r4 [--seed N]""" import json, os, sys, posixpath from .cli import REPO, load_cfg, get_store from .scheduler import Controller from . import recovery, launcher from .exports import export_runs def r1(seed=801): cfg = load_cfg("development"); store = get_store(); ctl = Controller(REPO, store, cfg, cfg["nodes"]) existing = store.query("SELECT COUNT(*) AS n FROM runs WHERE split='recovery'")[0]["n"] runs = ctl.make_assignment("recovery", ["F1-dev-01", "F3-dev-01", "F6-dev-01"], 2, seed, arms=("A", "D"), start_seq=existing + 1) for m in runs: m.notes += "; R1 interrupt after 6th tool use then resume" ctl.register(runs) ids = [m.run_id for m in runs] res = ctl.run_many(ids, faults={rid: {"type": "interrupt", "trigger": {"after_tool_uses": 6}} for rid in ids}) export_runs(store, REPO); print(json.dumps([{k: v for k, v in x.items() if k != "evaluation"} for x in res], indent=1, default=str)) def r2(): store = get_store(); out = [] muts = {"F1-dev-01": None, "F6-dev-01": None} for m in store.list_runs(split="pilot"): if m["task_id"] not in muts: continue bundle = os.path.join(REPO, "tasks", "public_bundles", m["task_id"], "data") files = sorted((f for f in os.listdir(bundle) if f.endswith(".csv")), key=lambda f: -os.path.getsize(os.path.join(bundle, f))) if not files: continue data_file = posixpath.join("data", files[0]) # the largest CSV = the main input # mutate: multiply the LAST numeric field of the 2nd data line by 1.37 and add 1 (a non-identifier value; documented, inside the copy only) mutate = ("python3 -c \"import sys,re;p=sys.argv[1];L=open(p).read().split('\\n');i=2\n" "while i