diff --git a/OVERSEER-STATUS.md b/OVERSEER-STATUS.md index ce5bea6..d21e7d9 100644 --- a/OVERSEER-STATUS.md +++ b/OVERSEER-STATUS.md @@ -102,3 +102,5 @@ RQ2 RATIFIED (operator Andre, 2026-07-20, while blind) — observation-consisten - **RESULT — RESOLVED MIX (§8 H1∧H2 agree +, both exclude 0).** H1 pooled Spearman ρ(c_i,H_i), RUN-LEVEL cluster bootstrap = **+0.6244**, 95% BCa CI **[+0.5941, +0.6545]** → mix. H2 OLS dose-response slope (per-run mean-H on per-run mean top-3 conc, 270 clustered pts) = **+0.7052**, 95% BCa CI **[+0.6195, +0.7903]** → mix. H3 joint **RESOLVED = mix**. Holm over own family {H1-pooled, H2-slope} (size 2): both reject (p_adj=0). Effect+CI reported, never bare p. - HONEST DISCLOSURE (as commanded): the §7 dry pass already PREVIEWED this mix (ρ 0→+0.838); the battery QUANTIFIES an effect already visible at calibration; two-sided pre-commitment stood. The +ρ MIX plainly **QUALIFIES/CORRECTS the lead RQ2-P1 "shrink" headline as a unique-bridge artifact** — concentration RAISES anonymity (shared bridge = mix), opposite of the naive funnel. That correction IS the finding. Lead RQ2-P1 NOT re-litigated; pool ΔH would be EXPLORATORY (prereg §1). Both prereg SHAs intact. - SEALED IMMUTABLY: `output/sor-rq2p3-confirmatory/rq2p3-confirmatory-results.json` (SHA-256 `5fdcb379d8a2…`) + `SHA256SUMS`; `/output/` gitignored → anchors force-added into the STEP-2 stone. Byte-identical on re-run (determinism verified). Tests: `tests/test_sor_rq2p3_confirm.py` 7 passed; full SOR suite 201 passed (no regression, frozen instruments untouched). NEXT: STEP 3 (RQ3 confirmatory — re-probe grid, launch live if up). +- STEP 3 — RQ3 CONFIRMATORY battery LAUNCHED LIVE (D2 GO, grid UP). Grid re-probed via `grid.write_device_map` (real SSH+docker subprocess probes): reachable=3, isolated_engine_host_count=1 (laptop docker up), devices_down=[] (FULL), honourable=true; `sor-hop:latest` image present (16.8MB). Green preflight: both RQ3 calibration gates already green + a 1×1×2 LIVE rehearsal DELIVERED (real docker circuit, measured added-latency ~9.8s/circuit). New triple-locked launcher `cmd_chat/sor/rq3_confirmatory_run.py` (RQ3 analogue of confirmatory_run.py): lock1 operator token SOR_CONFIRMATORY_GO=1, lock2 LEAD prereg SHA f22331a72e… verified (RQ3 is in the frozen lead family-of-7), lock3 assert_isolated(docker != local). All three armed ("[RQ3 GO] all locks armed"). +- RUNNING (do NOT trim): `executor.run_rq3_battery(live=True)` collecting the full frozen schedule — selector∈{static,random,agent} × pinned churn kp30/steps20, R=30 × C=50 = 4,500 real isolated-docker circuits (~12h est. at ~9.8s/circuit). Launch dir `output/sor-rq3-confirmatory/20260722T040640Z/confirmatory-data/` (gitignored; force-add anchors on completion). Verified genuinely progressing: python PID 51087 alive + live 4-container circuit (client+3 hops) up on docker. **Completion-detection: `rq3-battery-results.json` written once at end; progress = count of `rq3-*/rq3-run.json` sidecars → 90 (3 cells × 30 runs).** Containment intact (isolated-docker only, self-traffic, $0 — local heuristic/random arms; no frontier spend). Both prereg SHAs intact; worktree-only. Analysis (RQ3-P1-perf/latency, RQ3-P2, Holm-7) runs AFTER completion on the sealed record. diff --git a/cmd_chat/sor/rq3_confirmatory_run.py b/cmd_chat/sor/rq3_confirmatory_run.py new file mode 100644 index 0000000..9820dda --- /dev/null +++ b/cmd_chat/sor/rq3_confirmatory_run.py @@ -0,0 +1,94 @@ +"""RQ3 confirmatory battery — operator-gated LIVE launcher (triple-locked). + +The RQ3 family (RQ3-P1-perf, RQ3-P1-latency, RQ3-P2) is part of the **frozen LEAD +prereg** (`sor-consent-prereg.md` §3/§6, family-of-7); the companion run-brief +(`docs/rq3-companion-run-brief.md`) pins the churn params (kp=30, steps=20) and the +selector arms. This launcher is the RQ3 analogue of ``confirmatory_run.py``: it +collects the confirmatory battery ONLY behind the same triple-lock the lead battery +uses, because the RQ3-P1-latency DV is a **real end-to-end measurement** on isolated +docker circuits — nothing here is fabricated. + +Triple-lock (all three or refuse): + 1. **Operator token** — ``SOR_CONFIRMATORY_GO=1`` in the environment. + 2. **Frozen-prereg SHA-256** — the on-disk lead prereg still hashes to the pinned + value (``confirmatory_run.verify_freeze``); no run against an unfrozen/edited prereg. + 3. **Isolation** — ``assert_isolated(engine)`` (``engine != local``); every hop runs + in an isolated docker container, never on the host (CLAUDE.md §Containment). + +Green-preflight preconditions (checked, not fabricated): the two RQ3 calibration +gates (churn-bites + rebuild-classifier) already pass; the grid is up with >=1 +isolated engine host; the ``sor-hop`` image is present; a 1x1x2 live rehearsal +delivered. Then ``executor.run_rq3_battery(live=True)`` runs the full frozen +schedule (selector ∈ {static, random, agent} × pinned churn, R runs × C circuits) — +cells are NOT trimmed. Progress: per-run ``rq3-run.json`` sidecars appear under the +data dir; completion: ``rq3-battery-results.json`` is written once at the end. +""" + +from __future__ import annotations + +import argparse +import os +import sys +from datetime import datetime, timezone +from pathlib import Path + +from cmd_chat.sor import battery +from cmd_chat.sor.confirmatory_run import OPERATOR_TOKEN_ENV, verify_freeze +from cmd_chat.sor.forwarder import assert_isolated + + +def _ts() -> str: + return datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ") + + +def _refuse(reason: str) -> int: + print(f"[RQ3 GO REFUSED] {reason}", file=sys.stderr) + return 2 + + +def main(argv=None) -> int: + ap = argparse.ArgumentParser( + prog="python -m cmd_chat.sor.rq3_confirmatory_run", + description="RQ3 confirmatory battery: triple-locked human-gated LIVE data run.", + ) + ap.add_argument("--out", default=f"output/sor-rq3-confirmatory/{_ts()}") + ap.add_argument("--engine", default="docker") + ap.add_argument("--order-seed", type=int, default=battery.S0) + ap.add_argument("--r-runs", type=int, default=battery.R_RUNS) + ap.add_argument("--c-circuits", type=int, default=battery.C_CIRCUITS) + ap.add_argument("--pool-size", type=int, default=8) + ap.add_argument("--hops", type=int, default=3) + args = ap.parse_args(argv) + + # --- triple-lock ------------------------------------------------------- # + if os.environ.get(OPERATOR_TOKEN_ENV) != "1": + return _refuse(f"operator token missing (set {OPERATOR_TOKEN_ENV}=1)") + if not verify_freeze(): + return _refuse("frozen LEAD prereg SHA-256 mismatch — refusing to run against an unfrozen prereg") + try: + assert_isolated(args.engine) + except Exception as exc: # noqa: BLE001 + return _refuse(f"containment: {exc}") + + from cmd_chat.sor import executor + + data_dir = Path(args.out) / "confirmatory-data" + print(f"[RQ3 GO] all locks armed — collecting LIVE RQ3 battery " + f"(selector arms × churn kp{battery.RQ3_KILL_PROB_PCT}s{battery.RQ3_CHURN_STEPS}, " + f"R={args.r_runs} C={args.c_circuits}) into {data_dir}", flush=True) + try: + doc = executor.run_rq3_battery( + data_dir, engine=args.engine, order_seed=args.order_seed, + r_runs=args.r_runs, c_circuits=args.c_circuits, + pool_size=args.pool_size, hops=args.hops, live=True, + ) + except executor.ExecutorError as exc: + return _refuse(f"executor refused (no fabricated DV): {exc}") + + print(f"[RQ3 GO] battery collected: {doc['n_runs']} runs " + f"(measured_from={doc['measured_from']}) -> {doc['_results_path']}", flush=True) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())