RQ1+RQ2 start-line: live per-cell condition assembler + guarded launcher + Holm ratification

Wire the live per-cell condition assembler (cmd_chat/sor/assembler.py): compose
the existing R1/R4/R5/R6 pieces into a condition-encoding CircuitSpec per frozen
§2 cell, so a cell_id maps to a genuinely distinct, ForwarderPlan-gated
(engine != local) isolated circuit rather than the plain 3-hop control:
  - RQ1 bridge-on / on+padding insert a live bridge hop (+ R1 PADDING stream);
  - RQ2 bridge-/directory-federated genuinely span >= 2 houses
    (federation.select_federated_path, split-knowledge).
Plans only: opens no socket, moves no traffic, stands up no engine.

battery.assembler_dry_check validates on FIXTURES (6/6 cells distinct
fingerprints, all isolation-gated, same (cell,seed) reproduces, RQ1 bridge +
padding arms live, RQ2 federation >= 2 houses); write-once, kept out of any
confirmatory data dir. confirmatory_run preflight now runs it; the --operator-go
path no longer refuses cells as "not wired" — triple-lock + green preflight HOLD
on grid completion, then surface the operator's immutable data-run gate. No
confirmatory cell is ever fabricated.

Start-line instrument-validation gate (cmd_chat/sor/gate.py), grid + containment
pin (grid.py), and the guarded launcher (confirmatory_run.py) land alongside.

Holm: hold family_size = 7, report the 4 RQ1/RQ2 tests -> multipliers 7,6,5,4.
This is the pre-registration, not a deviation (prereg §6 [APPROVAL] size-7 family
+ D6 disclosure in the lead paper); docs/stage-05-holm-clarification.md marked
RATIFIED. RQ3-fold and alpha-split declined.

Containment intact; prereg untouched (SHA f22331a72e...); worktree-only. output/
gitignored (runtime artifacts, never source). Full SOR suite 156 passed. No
confirmatory data collected — the live data run remains the human gate.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
leetcrypt
2026-07-19 20:49:12 -07:00
parent 72a6c7b519
commit 6d61c53152
11 changed files with 1228 additions and 0 deletions
+184
View File
@@ -0,0 +1,184 @@
"""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 still 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 — and even with all three plus a green preflight it
**HOLDS on grid completion**: the confirmatory battery does not launch until the
full physical grid is up (the operator is bringing the 3rd phone online). This
launcher surfaces that hold; it never fabricates a confirmatory cell.
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)")
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 immutable confirmatory
# data run is still the human's to launch. This launcher surfaces readiness;
# the physical data collection is initiated by the operator, not fabricated.
return _refuse_go(
"human gate: grid complete and preflight green — the immutable confirmatory "
"data run is the operator's to initiate on the live grid. This launcher "
"does not fabricate confirmatory cells."
)
if __name__ == "__main__": # pragma: no cover
raise SystemExit(main())