Prepare the RPF-WP-0015-T03 synthetic E2 window: receipt generator and readiness record.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 236506@bnt-lap001 Assistant-Session: 09087018-91e1-48c5-ab2f-acfbb62c92e4
This commit is contained in:
parent
7624cfcdca
commit
a7392437e1
3 changed files with 107 additions and 1 deletions
56
scripts/rpf-wp-0015-e2-receipt.py
Executable file
56
scripts/rpf-wp-0015-e2-receipt.py
Executable file
|
|
@ -0,0 +1,56 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Write the RPF-WP-0015-T03 synthetic E2 approval receipt for one founder window.
|
||||
|
||||
Usage: scripts/rpf-wp-0015-e2-receipt.py OUTPUT.json [--start-in-min N]
|
||||
|
||||
The window is 15 minutes and starts now, or N minutes from now. Writing the
|
||||
receipt and running the window is the founder GO for that window; D5
|
||||
(2fd5849c) authorizes the exercise class only. The owner acknowledgements are
|
||||
the round-9 approvals of review contract 014627d6 (audit-core 0d0da0d2,
|
||||
rapp-postgres 6d047a08, railiance-platform c4a80a60). They stay valid only
|
||||
while the pinned artifacts in interfaces/RAILIANCE-WP-0024-owner-reviews.json
|
||||
are unchanged; the script refuses otherwise. The receipt holds no credential
|
||||
values. It refuses to overwrite an existing file.
|
||||
"""
|
||||
import hashlib
|
||||
import json
|
||||
import sys
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
pins = json.loads((ROOT / "interfaces/RAILIANCE-WP-0024-owner-reviews.json").read_text())["artifact_sha256"]
|
||||
drift = [p for p, h in pins.items() if hashlib.sha256((ROOT / p).read_bytes()).hexdigest() != h]
|
||||
if drift:
|
||||
sys.exit("owner-reviewed artifacts changed since contract 014627d6; new owner approvals needed: " + ", ".join(drift))
|
||||
if len(sys.argv) < 2:
|
||||
sys.exit(__doc__)
|
||||
out = sys.argv[1]
|
||||
delay = int(sys.argv[sys.argv.index('--start-in-min') + 1]) if '--start-in-min' in sys.argv else 0
|
||||
start = datetime.now(timezone.utc).replace(second=0, microsecond=0) + timedelta(minutes=delay)
|
||||
end = start + timedelta(minutes=15)
|
||||
tag = start.strftime('%Y%m%dt%H%M')
|
||||
z = lambda t: t.strftime('%Y-%m-%dT%H:%M:%SZ')
|
||||
receipt = {
|
||||
"procedure": "audit-core-database-lease-recovery",
|
||||
"task_id": "RAILIANCE-WP-0024-T03",
|
||||
"status": "approved",
|
||||
"approval_id": f"rpf-wp-0015-t03-e2-{tag}z-founder-go",
|
||||
"window": {"start": z(start), "end": z(end)},
|
||||
"abort_operator": "founder (platform-root), attended",
|
||||
"owners": {
|
||||
"audit-core": {"acknowledged": True, "message_id": "0d0da0d2-36a1-4ffc-b7bf-7896fad691f6"},
|
||||
"rapp-postgres": {"acknowledged": True, "message_id": "6d047a08-e9c8-4dbf-95b9-dca039791329"},
|
||||
"railiance-platform": {"acknowledged": True, "message_id": "c4a80a60-a415-4f2b-8928-751407473641"},
|
||||
},
|
||||
"synthetic_load": {"contract_id": "RAILIANCE-WP-0024-T02-SYNTHETIC-01",
|
||||
"driver_revision": "sha256:941ba251f638869626b06e9cbf430c70188c0bdf4715e3eff9c7610366f68662"},
|
||||
"synthetic_sender": {"identity": f"t03-e2-synthetic-sender-{start:%Y%m%d}",
|
||||
"source": f"t03-e2-synthetic-{start:%Y%m%d}",
|
||||
"tenant": f"tenant:trial:t03-e2-synthetic-{start:%Y%m%d}",
|
||||
"expires_at": z(end)},
|
||||
}
|
||||
with open(out, 'x') as f:
|
||||
json.dump(receipt, f, indent=2); f.write('\n')
|
||||
print(json.dumps({"approval_id": receipt["approval_id"], "window": receipt["window"],
|
||||
"confirm": f"audit-core-synthetic-sender:{receipt['approval_id']}:attended"}))
|
||||
35
tests/test_rpf_wp_0015_e2_receipt.py
Normal file
35
tests/test_rpf_wp_0015_e2_receipt.py
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
"""The E2 receipt generator emits a receipt the sender lane accepts as T03."""
|
||||
import importlib.util
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from datetime import UTC, datetime
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def lane():
|
||||
sys.path.insert(0, str(ROOT / "scripts"))
|
||||
spec = importlib.util.spec_from_file_location("lane_e2", ROOT / "scripts/audit_core_synthetic_sender_lane.py")
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
def test_receipt_is_accepted_by_the_lane_as_t03(tmp_path):
|
||||
out = tmp_path / "approval.json"
|
||||
printed = json.loads(subprocess.run([sys.executable, str(ROOT / "scripts/rpf-wp-0015-e2-receipt.py"), str(out)],
|
||||
check=True, capture_output=True, text=True).stdout)
|
||||
m = lane()
|
||||
approval, spec = m.load_receipt(out, datetime.now(UTC), require_open_window=True)
|
||||
assert approval["task_id"] == "RAILIANCE-WP-0024-T03"
|
||||
assert printed["confirm"] == m.confirm_token(approval)
|
||||
|
||||
|
||||
def test_refuses_to_overwrite(tmp_path):
|
||||
out = tmp_path / "approval.json"
|
||||
out.write_text("{}")
|
||||
result = subprocess.run([sys.executable, str(ROOT / "scripts/rpf-wp-0015-e2-receipt.py"), str(out)],
|
||||
capture_output=True, text=True)
|
||||
assert result.returncode != 0 and out.read_text() == "{}"
|
||||
|
|
@ -9,7 +9,7 @@ flavor: residual
|
|||
owner: codex
|
||||
topic_slug: railiance
|
||||
created: "2026-08-22"
|
||||
updated: "2026-10-14"
|
||||
updated: "2026-11-03"
|
||||
related:
|
||||
- AUDIT-WP-0008
|
||||
- WH-ENG-20260822-AUDIT-E2-01
|
||||
|
|
@ -535,3 +535,18 @@ and warden failed closed with self-revocation. Nothing was projected and audit-c
|
|||
untouched. Next: sign out of KeyCape (or use a fresh private window), complete
|
||||
password+OTP (aal2), reissue a near E2 receipt and run the launcher once. T03 stays
|
||||
`wait` until that E2 evidence exists.
|
||||
|
||||
E2 window prepared 2026-11-03. No new owner round is needed. Receipt
|
||||
acknowledgements are the owners' approval receipts for the review contract,
|
||||
not per-window sign-offs; T02 used the `ea3f53d6` approvals the same way. All
|
||||
pinned artifacts in `interfaces/RAILIANCE-WP-0024-owner-reviews.json` still
|
||||
match round 9 (contract `014627d6`: audit-core `0d0da0d2`, rapp-postgres
|
||||
`6d047a08`, railiance-platform `c4a80a60`). The load driver
|
||||
(`audit-core/scripts/t02_synthetic_load_driver.py`) still has revision
|
||||
`sha256:941ba251…`. The installed ops-warden contains `6e14300`.
|
||||
`scripts/rpf-wp-0015-e2-receipt.py` writes the 15-minute receipt and prints
|
||||
the confirm string. It refuses if any pinned artifact has changed, and the
|
||||
sender lane accepts its receipt as T03
|
||||
(`tests/test_rpf_wp_0015_e2_receipt.py`). The 2026-10-14/15 blocker was the
|
||||
KeyCape session at `aal1`. The window needs a fresh password+OTP (`aal2`)
|
||||
login, and its start must not fall within 20 minutes of 03:17 UTC.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue