Files
hack-house/cmd_chat/sor/confirmatory_run.py
T
leetcrypt ce68d41348 feat(sor): confirmatory data-collection executor (anti-fabrication)
Measures RQ1 bridge-correlation AUC + RQ2 Shannon entropy from REAL
per-hop pcaps of live isolated-docker circuits. run_battery(live=False)
hard-raises and the executor refuses (ExecutorError) any DV it did not
measure — the executor-side twin of the launcher's "never fabricate
cells" guard. Wired into confirmatory_run's triple-locked tokened GO
(executor.run_battery(live=True) behind operator token + verified frozen
prereg SHA + engine!=local + green preflight + full grid).

Containment intact: self-fixture bytes only, isolated engine only, no
external target. Frozen prereg untouched (SHA f22331a72e…).

Verify: test_sor_executor.py 7 + confirmatory_run + full SOR suite = 163
passed; preflight green (grid 3/3, READY); no confirmatory data collected.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-07-19 23:00:39 -07:00

211 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""RQ1+RQ2 confirmatory battery — start-line preflight + guarded launcher.
This is the single operator entrypoint. Run with **no flags** it performs the
*safe* start-line **preflight** and writes auditable artifacts, then prints a
GO/NO-GO summary and the exact launch command — it collects **no** confirmatory
data:
* §5 instrument-validation gate re-confirmation (``gate.run_gate``);
* grid inventory + containment pin (``grid.write_device_map``);
* frozen §2 cell plan + randomized/interleaved schedule (``battery.write_cell_plan``);
* a 1-cell × 2-run DRY provenance pass on fixtures (``battery.dry_pass``).
The live per-cell condition assembler is now wired (``sor.assembler``): each cell
maps to a genuinely distinct, condition-encoding, isolation-gated circuit (RQ1
bridge-on / on+padding arms actually insert a bridge hop + PADDING stream; RQ2
bridge-/directory-federated topologies genuinely span >= 2 houses). The preflight
proves this on FIXTURES (``battery.assembler_dry_check`` — plans only, no traffic).
The **immutable confirmatory data run on the real grid is the human gate**
(CLAUDE.md §Stop, GOAL envelope (b)). ``--operator-go`` is triple-locked — it
requires the ``SOR_CONFIRMATORY_GO=1`` operator token, a verified frozen-prereg
SHA-256, and an isolated engine — plus a green preflight and a full grid. When all
of those hold, this IS the operator's explicit GO and the wired data-collection
executor (``sor.executor``) collects the battery for real: it stands up each cell's
assembled circuit on the isolated engine, moves only self-generated fixture bytes,
and **measures the DVs from the real pcaps** (``executor.run_battery(live=True)``).
The executor refuses to emit any DV it did not measure — it never fabricates.
Containment is load-bearing: nothing here forwards real/third-party traffic,
touches an external target, or runs a forwarder on the host.
"""
from __future__ import annotations
import argparse
import hashlib
import os
import sys
from datetime import datetime, timezone
from pathlib import Path
from typing import Any, Dict
from cmd_chat.sor import battery, gate, grid
from cmd_chat.sor.forwarder import assert_isolated
# The frozen prereg (read-only source of truth) and its pinned SHA-256. A GO is
# refused unless the on-disk prereg still hashes to this — no confirmatory run
# against an unfrozen/edited prereg.
FROZEN_PREREG = Path.home() / "coding/sci-method/stages/03-design/output/sor-consent-prereg.md"
FROZEN_PREREG_SHA256 = "f22331a72e0d0ccf38b787e63acabbe9d666456ec76076787a6d545c3193425b"
OPERATOR_TOKEN_ENV = "SOR_CONFIRMATORY_GO"
def _ts() -> str:
return datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ")
def verify_freeze() -> bool:
"""True iff the on-disk frozen prereg still matches its pinned SHA-256."""
try:
got = hashlib.sha256(FROZEN_PREREG.read_bytes()).hexdigest()
except OSError:
return False
return got == FROZEN_PREREG_SHA256
def preflight(out_dir: Path, *, order_seed: int = battery.S0, allow_live_gate: bool = True) -> Dict[str, Any]:
"""Run the safe start-line preflight and write artifacts under ``out_dir``.
Collects no confirmatory data. Returns a summary with a GO/NO-GO verdict."""
out_dir = Path(out_dir)
g = gate.run_gate(out_dir / "gate", allow_live=allow_live_gate)
dm = grid.write_device_map(out_dir / "grid")
plan_path = battery.write_cell_plan(out_dir / "plan", order_seed=order_seed)
dp = battery.dry_pass(out_dir / "dry", runs=2)
asm = battery.assembler_dry_check(out_dir / "assembler")
ready = bool(
g["all_green"]
and dm["topology_matchedN_honourable"]
and dp["all_sha_match"] and dp["all_seed_reproduces"] and dp["distinct_seeds"]
and asm["all_green"]
and verify_freeze()
)
return {
"generated_utc": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
"out_dir": str(out_dir),
"gate_all_green": g["all_green"],
"gate_offline_green": g["offline_items_green"],
"grid_reachable": dm["reachable_count"],
"grid_engine_hosts": dm["isolated_engine_host_count"],
"grid_down": dm["devices_down"],
"grid_honourable": dm["topology_matchedN_honourable"],
"grid_full": len(dm["devices_down"]) == 0,
"cell_plan": str(plan_path),
"dry_ok": dp["all_sha_match"] and dp["all_seed_reproduces"] and dp["distinct_seeds"],
"assembler_ok": asm["all_green"],
"assembler_distinct": asm["distinct_fingerprints"],
"assembler_isolation_gated": asm["all_isolation_gated"],
"freeze_ok": verify_freeze(),
"preflight_ready": ready,
}
def _print_summary(s: Dict[str, Any]) -> None:
print(f"[preflight] artifacts -> {s['out_dir']}")
print(f"[preflight] gate all_green={s['gate_all_green']} "
f"(offline={s['gate_offline_green']})")
print(f"[preflight] grid reachable={s['grid_reachable']} "
f"engine_hosts={s['grid_engine_hosts']} down={s['grid_down']} "
f"honourable={s['grid_honourable']}")
print(f"[preflight] dry_ok={s['dry_ok']} freeze_ok={s['freeze_ok']}")
print(f"[preflight] assembler_ok={s['assembler_ok']} "
f"(distinct={s['assembler_distinct']} isolation_gated={s['assembler_isolation_gated']})")
print(f"[preflight] grid_full={s['grid_full']} READY={s['preflight_ready']}")
def _refuse_go(reason: str) -> int:
print(f"[GO REFUSED] {reason}", file=sys.stderr)
return 2
def main(argv=None) -> int:
ap = argparse.ArgumentParser(
prog="python -m cmd_chat.sor.confirmatory_run",
description="RQ1+RQ2 confirmatory battery: safe preflight by default; "
"--operator-go is the human-gated immutable data run.",
)
ap.add_argument("--out", default=f"output/sor-confirmatory/{_ts()}",
help="preflight artifact dir (default: timestamped)")
ap.add_argument("--order-seed", type=int, default=battery.S0,
help="measurement-side schedule ordering seed (default S0)")
ap.add_argument("--engine", default="docker", help="isolated engine (default docker)")
ap.add_argument("--operator-go", action="store_true",
help="attempt the human-gated confirmatory data run (triple-locked)")
ap.add_argument("--r-runs", type=int, default=battery.R_RUNS,
help=f"runs per cell (frozen §4 default R={battery.R_RUNS})")
ap.add_argument("--c-circuits", type=int, default=battery.C_CIRCUITS,
help=f"circuits per run (frozen §4 default C={battery.C_CIRCUITS})")
ap.add_argument("--hops", type=int, default=3, help="hops per circuit (default 3)")
ap.add_argument("--bins", type=int, default=32, help="pcap time-bins for the correlator")
args = ap.parse_args(argv)
out_dir = Path(args.out)
summary = preflight(out_dir, order_seed=args.order_seed)
_print_summary(summary)
go_cmd = (f"{OPERATOR_TOKEN_ENV}=1 python -m cmd_chat.sor.confirmatory_run "
f"--operator-go --engine {args.engine}")
if not args.operator_go:
print("\n[held] preflight only — no confirmatory data collected.")
print(f"[held] the immutable data run is the human gate. GO command:\n {go_cmd}")
return 0
# --- triple-locked GO path (human gate) --------------------------------- #
if os.environ.get(OPERATOR_TOKEN_ENV) != "1":
return _refuse_go(f"operator token missing (set {OPERATOR_TOKEN_ENV}=1)")
if not verify_freeze():
return _refuse_go("frozen prereg SHA-256 mismatch — refusing to run against an unfrozen prereg")
try:
assert_isolated(args.engine)
except Exception as exc: # noqa: BLE001
return _refuse_go(f"containment: {exc}")
if not summary["preflight_ready"]:
return _refuse_go("preflight not fully green — resolve NO-GO items before a data run")
# Triple-lock passes and the live per-cell condition assembler is wired +
# fixture-validated (assembler_ok). The one remaining gate is physical: the
# confirmatory battery HOLDS until the full grid is up. The operator is
# bringing the 3rd phone online; until every device is reachable this launcher
# refuses to launch a data run on a degraded grid rather than fabricate cells.
if not summary["grid_full"]:
return _refuse_go(
"grid completing: confirmatory battery holds until the full physical "
f"grid is up (devices down: {summary['grid_down']}). The live per-cell "
"assembler is wired + fixture-validated; the operator is bringing the "
"3rd phone online. Re-run --operator-go once the grid is complete."
)
# Full grid + all three locks + green preflight + the operator token: this IS
# the operator's explicit GO. Collect the confirmatory battery for real — the
# executor stands up each cell's assembled circuit on the isolated engine, moves
# only self-generated fixture bytes, and measures the DVs from the real pcaps.
# It refuses to emit any DV it did not measure (never fabricates).
from cmd_chat.sor import executor
data_dir = out_dir / "confirmatory-data"
print(f"\n[GO] all locks armed + grid full — collecting confirmatory battery "
f"(R={args.r_runs} C={args.c_circuits} hops={args.hops}) into {data_dir}")
try:
doc = executor.run_battery(
data_dir, engine=args.engine, order_seed=args.order_seed,
r_runs=args.r_runs, c_circuits=args.c_circuits, hops=args.hops,
bins=args.bins, live=True,
)
except executor.ExecutorError as exc:
return _refuse_go(f"executor refused (no fabricated DV): {exc}")
except Exception as exc: # noqa: BLE001
return _refuse_go(f"executor error during live collection: {exc}")
print(f"[GO] confirmatory battery collected: {doc['n_runs']} runs "
f"(measured_from={doc['measured_from']}) -> {doc['_results_path']}")
print("[GO] next: analysis/confirm.py CI-gate + Holm (family_size=7, report 4) "
"over the reported RQ1/RQ2 DVs.")
return 0
if __name__ == "__main__": # pragma: no cover
raise SystemExit(main())