Files
ai-contract-platform/yuqei-infra/scripts/apply-rc06-publication-batch.py
T

2186 lines
85 KiB
Python

#!/usr/bin/env python3
"""Protocol client for applying one frozen RC-06 batch through a real service.
The service contract is deliberately fail-closed. The exact 60 assets and 14
Prompt modules must be durably committed and read back online before the
offline apply authority can countersign them. This client never treats an
unsigned HTTP response as publication evidence.
The legal-source request/decision/keyring checked here is an externally signed
assertion. This program delegates identity, qualification, freshness, status
URL, rationale and exact source hashes to the canonical scene-review validator;
it does not perform legal review or infer professional status.
This file does not implement the cross-Contract/AI transaction service. RC-06
remains blocked until a deployed endpoint can truthfully produce the signed
cross-database saga and online read-back evidence required by this client.
"""
from __future__ import annotations
import argparse
import base64
import hashlib
import importlib.util
import json
import os
import sqlite3
import sys
import urllib.error
import urllib.parse
import urllib.request
from datetime import UTC, datetime
from pathlib import Path
from typing import Any, Mapping
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
SCRIPT_DIR = Path(__file__).resolve().parent
REPO_ROOT = SCRIPT_DIR.parents[1]
BUILDER_PATH = SCRIPT_DIR / "build-rc06-publication-batch.py"
def _load_builder():
spec = importlib.util.spec_from_file_location("rc06_publication_batch_builder", BUILDER_PATH)
if spec is None or spec.loader is None:
raise RuntimeError("cannot load RC-06 publication batch builder")
module = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = module
spec.loader.exec_module(module)
return module
batch = _load_builder()
SCENE_LEGAL_REVIEW_BUILDER_PATH = SCRIPT_DIR / "build-scene-source-legal-review.py"
APPLY_REQUEST_SCHEMA_VERSION = "yuqei.rc06-online-apply-request.v3"
APPLY_RESPONSE_SCHEMA_VERSION = "yuqei.rc06-online-apply-response.v2"
TRANSACTION_STATUS_SCHEMA_VERSION = "yuqei.rc06-online-transaction-status.v3"
ROLLBACK_REQUEST_SCHEMA_VERSION = "yuqei.rc06-online-rollback-request.v2"
ROLLBACK_RESPONSE_SCHEMA_VERSION = "yuqei.rc06-online-rollback-response.v2"
FINALIZE_REQUEST_SCHEMA_VERSION = "yuqei.rc06-online-finalize-request.v1"
FINALIZE_RESPONSE_SCHEMA_VERSION = "yuqei.rc06-online-finalize-response.v1"
EXECUTION_EVIDENCE_SCHEMA_VERSION = "yuqei.rc06-online-apply-evidence.v2"
FINAL_EVIDENCE_SCHEMA_VERSION = "yuqei.rc06-finalized-apply-evidence.v1"
LEDGER_SCHEMA_VERSION = "yuqei.rc06-local-apply-ledger.v2"
AUTH_TOKEN_ENV = "RC06_APPLY_BEARER_TOKEN"
MAX_HTTP_BODY_BYTES = 16 * 1024 * 1024
class ApplyPublicationError(batch.PublicationBatchError):
"""The online transaction could not be proven safe and complete."""
def _require_exact(value: Any, label: str, keys: tuple[str, ...]) -> dict[str, Any]:
if not isinstance(value, dict) or set(value) != set(keys):
raise ApplyPublicationError(f"{label} fields are invalid")
return value
def _require_text(value: Any, label: str, *, maximum: int = 512) -> str:
if not isinstance(value, str) or not value.strip() or value != value.strip() or len(value) > maximum:
raise ApplyPublicationError(f"{label} is invalid")
return value
def _sha256(value: bytes) -> str:
return hashlib.sha256(value).hexdigest()
def _public_raw(key: Ed25519PublicKey) -> bytes:
return key.public_bytes(serialization.Encoding.Raw, serialization.PublicFormat.Raw)
def _load_scene_legal_review_module():
if not SCENE_LEGAL_REVIEW_BUILDER_PATH.is_file():
raise ApplyPublicationError(
"scene legal review validator is absent from the frozen candidate"
)
spec = importlib.util.spec_from_file_location(
"rc06_scene_source_legal_review", SCENE_LEGAL_REVIEW_BUILDER_PATH
)
if spec is None or spec.loader is None:
raise ApplyPublicationError("cannot load scene legal review validator")
module = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = module
spec.loader.exec_module(module)
return module
def validate_scene_legal_review(
manifest: Mapping[str, Any],
approval: Mapping[str, Any],
request: Any,
decision: Any,
keyring: Any,
keyring_raw_sha256: str,
*,
now: datetime,
) -> tuple[dict[str, Any], str]:
"""Delegate legal verification and frozen-keyring trust to the builder."""
try:
return batch.validate_scene_legal_review_evidence(
REPO_ROOT,
manifest,
approval,
request,
decision,
keyring,
keyring_raw_sha256,
now=now,
validator=_load_scene_legal_review_module(),
)
except batch.PublicationBatchError as exc:
raise ApplyPublicationError(f"scene legal review validation failed: {exc}") from exc
def expected_runtime_snapshot_results(manifest: Mapping[str, Any]) -> list[dict[str, Any]]:
return batch.expected_runtime_snapshot_results(manifest)
def validate_runtime_snapshot_receipt(
manifest: Mapping[str, Any],
manifest_raw_sha256: str,
approval: Mapping[str, Any],
approval_raw_sha256: str,
legal_review_binding_sha256: str,
legal_review_expires_at: str,
apply_service_public_key: Ed25519PublicKey,
online_service_public_key: Any,
online_transaction_receipt: Mapping[str, Any],
receipt: Any,
*,
environment_id: str,
tenant_id: str,
) -> dict[str, Any]:
try:
return batch.validate_runtime_snapshot_receipt(
manifest,
manifest_raw_sha256,
approval_raw_sha256,
approval,
apply_service_public_key,
online_service_public_key,
online_transaction_receipt,
receipt,
legal_review_binding_sha256=legal_review_binding_sha256,
legal_review_expires_at=legal_review_expires_at,
environment_id=environment_id,
tenant_id=tenant_id,
)
except batch.PublicationBatchError as exc:
raise ApplyPublicationError(str(exc)) from exc
class JsonHttpClient:
def __init__(
self,
base_url: str,
bearer_token: str,
*,
timeout_seconds: float = 30.0,
allow_http_loopback: bool = False,
) -> None:
parsed = urllib.parse.urlsplit(base_url)
if parsed.username or parsed.password or parsed.query or parsed.fragment:
raise ApplyPublicationError("publication service URL contains forbidden components")
loopback = parsed.hostname in {"127.0.0.1", "localhost", "::1"}
if parsed.scheme != "https" and not (
allow_http_loopback and parsed.scheme == "http" and loopback
):
raise ApplyPublicationError("publication service requires HTTPS")
if not parsed.netloc or parsed.path not in {"", "/"}:
raise ApplyPublicationError("publication service base URL is invalid")
self.base_url = base_url.rstrip("/")
self.token = _require_text(bearer_token, "publication bearer token", maximum=8192)
self.timeout_seconds = timeout_seconds
def request(
self,
method: str,
path: str,
*,
payload: Mapping[str, Any] | None,
headers: Mapping[str, str],
) -> Any:
body = batch._canonical(payload) if payload is not None else None
request_headers = {
"Accept": "application/json",
"Authorization": f"Bearer {self.token}",
**dict(headers),
}
if body is not None:
request_headers["Content-Type"] = "application/json"
request = urllib.request.Request(
self.base_url + path,
data=body,
headers=request_headers,
method=method,
)
try:
response = urllib.request.urlopen(request, timeout=self.timeout_seconds)
raw = response.read(MAX_HTTP_BODY_BYTES + 1)
status = response.status
content_type = response.headers.get_content_type()
except urllib.error.HTTPError as exc:
raw = exc.read(MAX_HTTP_BODY_BYTES + 1)
detail = f"HTTP {exc.code}"
try:
parsed = json.loads(raw.decode("utf-8"))
if isinstance(parsed, dict) and isinstance(parsed.get("error"), str):
detail += f": {parsed['error'][:512]}"
except (UnicodeDecodeError, json.JSONDecodeError):
pass
raise ApplyPublicationError(f"publication service rejected request ({detail})") from exc
except (OSError, TimeoutError) as exc:
raise ApplyPublicationError("publication service request failed") from exc
if status < 200 or status >= 300 or content_type != "application/json":
raise ApplyPublicationError("publication service returned an invalid HTTP response")
if len(raw) > MAX_HTTP_BODY_BYTES:
raise ApplyPublicationError("publication service response is too large")
try:
return json.loads(
raw.decode("utf-8"),
object_pairs_hook=batch._reject_duplicate_json_pairs,
parse_constant=batch._reject_json_constant,
)
except (UnicodeDecodeError, json.JSONDecodeError) as exc:
raise ApplyPublicationError("publication service response is not valid JSON") from exc
class ApplyLedger:
"""Small local recovery ledger; it stores hashes/receipts, never credentials."""
def __init__(self, path: Path) -> None:
self.path = path.resolve()
self.path.parent.mkdir(parents=True, exist_ok=True)
self.connection = sqlite3.connect(self.path, timeout=30, isolation_level=None)
self.connection.execute("PRAGMA journal_mode=WAL")
self.connection.execute("PRAGMA synchronous=FULL")
legacy_operations_present = self.connection.execute(
"SELECT 1 FROM sqlite_master WHERE type='table' AND name='rc06_apply_operations'"
).fetchone() is not None
self.connection.executescript(
"""
CREATE TABLE IF NOT EXISTS rc06_apply_ledger_metadata (
singleton INTEGER PRIMARY KEY CHECK(singleton = 1),
schema_version TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS rc06_apply_operations (
idempotency_key TEXT PRIMARY KEY,
request_sha256 TEXT NOT NULL,
state TEXT NOT NULL,
apply_receipt_json TEXT,
apply_receipt_sha256 TEXT,
last_error TEXT,
updated_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS rc06_apply_events (
sequence INTEGER PRIMARY KEY AUTOINCREMENT,
idempotency_key TEXT NOT NULL,
state TEXT NOT NULL,
evidence_sha256 TEXT NOT NULL,
recorded_at TEXT NOT NULL
);
"""
)
metadata = self.connection.execute(
"SELECT schema_version FROM rc06_apply_ledger_metadata WHERE singleton = 1"
).fetchone()
if metadata is None:
if legacy_operations_present:
raise ApplyPublicationError(
"legacy apply ledger cannot be silently upgraded; use a new ledger path"
)
self.connection.execute(
"INSERT INTO rc06_apply_ledger_metadata(singleton, schema_version) VALUES (1, ?)",
(LEDGER_SCHEMA_VERSION,),
)
elif metadata[0] != LEDGER_SCHEMA_VERSION:
raise ApplyPublicationError("apply ledger schema is unsupported")
def reserve(
self,
key: str,
request_sha256: str,
now: datetime,
*,
initial_dispatch_authorized: bool,
) -> tuple[str, dict[str, Any] | None]:
"""Reserve a new request or identify an exact crash-recovery replay.
An expired short-lived challenge may recover an already-dispatched exact
request, but it must never create a new dispatch reservation.
"""
self.connection.execute("BEGIN IMMEDIATE")
try:
row = self.connection.execute(
"SELECT request_sha256, state, apply_receipt_json FROM rc06_apply_operations "
"WHERE idempotency_key = ?",
(key,),
).fetchone()
if row is not None and row[0] != request_sha256:
raise ApplyPublicationError("idempotency key is bound to another request")
if row is not None and row[1] in {
"online_committed_pending_countersign",
"succeeded",
}:
receipt = json.loads(row[2])
self.connection.execute("COMMIT")
return "replay", receipt
if row is not None and row[1] in {
"dispatching",
"verifying",
"irreversible_failure_no_go",
}:
timestamp = now.astimezone(UTC).isoformat(timespec="seconds")
self._event(
key,
f"recovering_{row[1]}",
request_sha256,
timestamp,
)
self.connection.execute("COMMIT")
return "recover", None
if row is not None:
raise ApplyPublicationError("an apply with this idempotency key needs reconciliation")
timestamp = now.astimezone(UTC).isoformat(timespec="seconds")
if not initial_dispatch_authorized:
self.connection.execute(
"INSERT INTO rc06_apply_operations "
"(idempotency_key, request_sha256, state, updated_at) "
"VALUES (?, ?, 'probing_remote', ?)",
(key, request_sha256, timestamp),
)
self._event(key, "probing_remote", request_sha256, timestamp)
self.connection.execute("COMMIT")
return "probe", None
self.connection.execute(
"INSERT INTO rc06_apply_operations "
"(idempotency_key, request_sha256, state, updated_at) VALUES (?, ?, 'dispatching', ?) "
"ON CONFLICT(idempotency_key) DO UPDATE SET state='dispatching', last_error=NULL, updated_at=excluded.updated_at",
(key, request_sha256, timestamp),
)
self._event(key, "dispatching", request_sha256, timestamp)
self.connection.execute("COMMIT")
return "dispatch", None
except Exception:
self.connection.execute("ROLLBACK")
raise
def load(self, key: str, request_sha256: str) -> tuple[str, dict[str, Any]]:
row = self.connection.execute(
"SELECT request_sha256, state, apply_receipt_json FROM rc06_apply_operations "
"WHERE idempotency_key = ?",
(key,),
).fetchone()
if row is None or row[0] != request_sha256 or row[2] is None:
raise ApplyPublicationError("online execution evidence is absent from the ledger")
try:
evidence = json.loads(row[2])
except (TypeError, json.JSONDecodeError) as exc:
raise ApplyPublicationError("stored online execution evidence is invalid") from exc
return str(row[1]), evidence
def state(
self,
key: str,
state: str,
evidence: Any,
now: datetime,
*,
receipt: Mapping[str, Any] | None = None,
error: str | None = None,
) -> None:
evidence_sha = batch._sha256_json(evidence)
receipt_json = (
batch._canonical(receipt).decode("utf-8") if receipt is not None else None
)
receipt_sha = batch._sha256_json(receipt) if receipt is not None else None
timestamp = now.astimezone(UTC).isoformat(timespec="seconds")
self.connection.execute("BEGIN IMMEDIATE")
try:
self.connection.execute(
"UPDATE rc06_apply_operations SET state=?, apply_receipt_json=?, "
"apply_receipt_sha256=?, last_error=?, updated_at=? WHERE idempotency_key=?",
(state, receipt_json, receipt_sha, error, timestamp, key),
)
self._event(key, state, evidence_sha, timestamp)
self.connection.execute("COMMIT")
except Exception:
self.connection.execute("ROLLBACK")
raise
def _event(self, key: str, state: str, evidence_sha: str, timestamp: str) -> None:
self.connection.execute(
"INSERT INTO rc06_apply_events "
"(idempotency_key, state, evidence_sha256, recorded_at) VALUES (?, ?, ?, ?)",
(key, state, evidence_sha, timestamp),
)
def close(self) -> None:
self.connection.close()
def _idempotency_key(
manifest_raw_sha256: str,
approval_raw_sha256: str,
legal_review_binding_sha256: str,
environment_id: str,
tenant_id: str,
) -> str:
return batch.publication_idempotency_key(
manifest_raw_sha256,
approval_raw_sha256,
legal_review_binding_sha256,
environment_id,
tenant_id,
)
def _transaction_id(idempotency_key: str) -> str:
return batch.publication_transaction_id(idempotency_key)
def _headers(
key: str,
manifest_raw_sha256: str,
approval_raw_sha256: str,
legal_review_binding_sha256: str,
tenant_id: str,
) -> dict[str, str]:
return {
"Idempotency-Key": key,
"X-RC06-Manifest-SHA256": manifest_raw_sha256,
"X-RC06-Approval-SHA256": approval_raw_sha256,
"X-RC06-Legal-Review-SHA256": legal_review_binding_sha256,
"X-RC06-Tenant-ID": tenant_id,
}
def _validate_apply_response(
response: Any,
*,
key: str,
request_sha256: str,
legal_review_binding_sha256: str,
legal_review_expires_at: str,
transaction_id: str,
environment_id: str,
tenant_id: str,
) -> dict[str, Any]:
row = _require_exact(
response,
"online apply response",
(
"schema_version",
"idempotency_key",
"request_sha256",
"legal_source_review_binding_sha256",
"legal_source_review_expires_at",
"transaction_id",
"environment_id",
"tenant_id",
"transaction_mode",
"cross_database_atomicity",
"publication_item_count",
"runtime_snapshot_dependency_count",
"online_transaction_receipt",
"runtime_snapshot_receipt",
),
)
if (
row["schema_version"] != APPLY_RESPONSE_SCHEMA_VERSION
or row["idempotency_key"] != key
or row["request_sha256"] != request_sha256
or row["legal_source_review_binding_sha256"] != legal_review_binding_sha256
or row["legal_source_review_expires_at"] != legal_review_expires_at
or row["transaction_id"] != transaction_id
or row["environment_id"] != environment_id
or row["tenant_id"] != tenant_id
or row["transaction_mode"] != batch.TRANSACTION_MODE
or row["cross_database_atomicity"] is not False
or row["publication_item_count"] != 74
or row["runtime_snapshot_dependency_count"] != 14
):
raise ApplyPublicationError("online apply response identity or transaction mode drift")
return row
_TRANSACTION_STATUS_FIELDS = (
"schema_version",
"idempotency_key",
"request_sha256",
"transaction_id",
"state",
"state_version",
"no_go",
"legal_source_review_binding_sha256",
"environment_id",
"tenant_id",
"transaction_mode",
"cross_database_atomicity",
"publication_item_results",
"publication_item_count",
"runtime_snapshot_dependencies",
"runtime_snapshot_dependency_count",
"participant_evidence",
"online_transaction_receipt",
"online_transaction_receipt_sha256",
"runtime_snapshot_receipt",
"runtime_snapshot_receipt_sha256",
"apply_receipt",
"apply_receipt_sha256",
"finalized_at",
"rollback_response",
"rollback_response_sha256",
"failure_code",
"failure_at",
"failure_evidence_sha256",
"status_updated_at",
)
_TRANSACTION_STATE_VERSION = {
"prepared": 1,
"rolled_back": 2,
# This is the post-Contract-commit, no-rollback boundary. Replaying the
# exact request may still recover read-back/KMS evidence and advance to 3.
"irreversible_failure": 2,
"committed_and_verified": 3,
"finalized": 4,
}
def _validate_transaction_status(
status: Any,
*,
manifest: Mapping[str, Any],
manifest_raw_sha256: str,
approval: Mapping[str, Any],
approval_raw_sha256: str,
approval_keyring: Mapping[str, Any],
approval_root_public_key: Ed25519PublicKey,
apply_service_public_key: Ed25519PublicKey,
online_service_public_key: Any,
request_sha256: str,
key: str,
transaction_id: str,
legal_review_binding_sha256: str,
legal_review_expires_at: str,
environment_id: str,
tenant_id: str,
minimum_state_version: int = 1,
expected_apply_receipt: Mapping[str, Any] | None = None,
) -> dict[str, Any]:
"""Validate the one exact forward GET status contract for every client."""
row = _require_exact(status, "online transaction status", _TRANSACTION_STATUS_FIELDS)
state = row["state"]
expected_state_version = _TRANSACTION_STATE_VERSION.get(state)
if (
row["schema_version"] != TRANSACTION_STATUS_SCHEMA_VERSION
or row["idempotency_key"] != key
or row["request_sha256"] != request_sha256
or row["transaction_id"] != transaction_id
or expected_state_version is None
or not isinstance(row["state_version"], int)
or isinstance(row["state_version"], bool)
or row["state_version"] != expected_state_version
or row["state_version"] < minimum_state_version
or row["no_go"] is not (state != "finalized")
or row["legal_source_review_binding_sha256"] != legal_review_binding_sha256
or row["environment_id"] != environment_id
or row["tenant_id"] != tenant_id
or row["transaction_mode"] != batch.TRANSACTION_MODE
or row["cross_database_atomicity"] is not False
):
raise ApplyPublicationError("online transaction status identity or state drift")
batch._require_sha(row["request_sha256"], "online status request SHA-256")
status_updated_at = batch._parse_time(
row["status_updated_at"], "online status_updated_at"
)
commit_empty = (
row["publication_item_results"] == []
and row["publication_item_count"] == 0
and row["runtime_snapshot_dependencies"] == []
and row["runtime_snapshot_dependency_count"] == 0
and row["participant_evidence"] == []
and row["online_transaction_receipt"] is None
and row["online_transaction_receipt_sha256"] is None
and row["runtime_snapshot_receipt"] is None
and row["runtime_snapshot_receipt_sha256"] is None
)
final_empty = (
row["apply_receipt"] is None
and row["apply_receipt_sha256"] is None
and row["finalized_at"] is None
)
rollback_empty = (
row["rollback_response"] is None
and row["rollback_response_sha256"] is None
)
failure_empty = (
row["failure_code"] is None
and row["failure_at"] is None
and row["failure_evidence_sha256"] is None
)
if state in {"prepared", "irreversible_failure", "rolled_back"} and not commit_empty:
raise ApplyPublicationError("non-committed online status contains commit evidence")
if state != "finalized" and not final_empty:
raise ApplyPublicationError("non-finalized online status contains finalization evidence")
if state != "rolled_back" and not rollback_empty:
raise ApplyPublicationError("non-rollback online status contains rollback evidence")
if state != "irreversible_failure" and not failure_empty:
raise ApplyPublicationError("non-failure online status contains failure evidence")
if state == "prepared":
if not rollback_empty or not failure_empty:
raise ApplyPublicationError("prepared online status evidence is invalid")
return row
if state == "rolled_back":
rollback = _validate_rollback_response(
row["rollback_response"],
manifest=manifest,
key=key,
transaction_id=transaction_id,
)
if row["rollback_response_sha256"] != batch._sha256_json(rollback):
raise ApplyPublicationError("online rollback status hash drift")
return row
if state == "irreversible_failure":
_require_text(row["failure_code"], "online failure_code", maximum=128)
failure_at = batch._parse_time(row["failure_at"], "online failure_at")
batch._require_sha(
row["failure_evidence_sha256"], "online failure evidence SHA-256"
)
if failure_at > status_updated_at:
raise ApplyPublicationError("online failure postdates its status update")
return row
expected_publication_results = batch._expected_apply_item_results(manifest)
expected_runtime_results = expected_runtime_snapshot_results(manifest)
online_transaction_receipt = row["online_transaction_receipt"]
runtime_snapshot_receipt = row["runtime_snapshot_receipt"]
if not isinstance(online_transaction_receipt, dict) or not isinstance(
runtime_snapshot_receipt, dict
):
raise ApplyPublicationError("committed online status omits signed receipt evidence")
online_receipt = batch.validate_online_transaction_receipt(
manifest,
manifest_raw_sha256,
approval_raw_sha256,
approval,
apply_service_public_key,
online_service_public_key,
online_transaction_receipt,
legal_review_binding_sha256=legal_review_binding_sha256,
legal_review_expires_at=legal_review_expires_at,
environment_id=environment_id,
tenant_id=tenant_id,
)
batch.validate_runtime_snapshot_receipt(
manifest,
manifest_raw_sha256,
approval_raw_sha256,
approval,
apply_service_public_key,
online_service_public_key,
online_receipt,
runtime_snapshot_receipt,
legal_review_binding_sha256=legal_review_binding_sha256,
legal_review_expires_at=legal_review_expires_at,
environment_id=environment_id,
tenant_id=tenant_id,
)
if (
row["publication_item_results"] != expected_publication_results
or row["publication_item_results"]
!= online_transaction_receipt["payload"]["item_results"]
or row["publication_item_count"] != 74
or row["runtime_snapshot_dependencies"] != expected_runtime_results
or row["runtime_snapshot_dependencies"]
!= runtime_snapshot_receipt["payload"]["runtime_snapshot_dependencies"]
or row["runtime_snapshot_dependency_count"] != 14
or row["participant_evidence"]
!= online_transaction_receipt["payload"]["participant_evidence"]
or row["online_transaction_receipt_sha256"]
!= batch._sha256_json(online_transaction_receipt)
or row["runtime_snapshot_receipt_sha256"]
!= batch._sha256_json(runtime_snapshot_receipt)
or not rollback_empty
or not failure_empty
):
raise ApplyPublicationError("online read-after-write receipt verification failed")
latest_commit_evidence_at = max(
batch._parse_time(
online_transaction_receipt["payload"]["committed_at"],
"online receipt committed_at",
),
batch._parse_time(
runtime_snapshot_receipt["payload"]["captured_at"],
"runtime snapshot captured_at",
),
)
if status_updated_at < latest_commit_evidence_at:
raise ApplyPublicationError("online status predates its signed commit evidence")
if state == "committed_and_verified":
if not final_empty:
raise ApplyPublicationError("committed status contains finalization evidence")
return row
apply_receipt = row["apply_receipt"]
if not isinstance(apply_receipt, dict):
raise ApplyPublicationError("finalized status omits the signed apply receipt")
batch.validate_apply_receipt(
manifest,
manifest_raw_sha256,
approval,
approval_keyring,
approval_root_public_key,
apply_service_public_key,
online_service_public_key,
approval_raw_sha256,
apply_receipt,
legal_review_binding_sha256=legal_review_binding_sha256,
legal_review_expires_at=legal_review_expires_at,
environment_id=environment_id,
tenant_id=tenant_id,
)
if (
apply_receipt["payload"]["online_transaction_receipt"]
!= online_transaction_receipt
or apply_receipt["payload"]["runtime_snapshot_receipt"]
!= runtime_snapshot_receipt
or row["apply_receipt_sha256"] != batch._sha256_json(apply_receipt)
or (
expected_apply_receipt is not None
and apply_receipt != expected_apply_receipt
)
):
raise ApplyPublicationError("finalized status receipt binding drift")
finalized_at = batch._parse_time(row["finalized_at"], "online finalized_at")
countersigned_at = batch._parse_time(
apply_receipt["payload"]["countersigned_at"], "apply countersigned_at"
)
if finalized_at < countersigned_at or status_updated_at < finalized_at:
raise ApplyPublicationError("online finalized status timestamp drift")
return row
def _validate_compensation_hashes(
item: Mapping[str, Any],
label: str,
*,
unchanged_preexisting_sha256: str | None = None,
) -> tuple[int, int, int]:
if item["status"] != "verified":
raise ApplyPublicationError(f"{label} status drift")
if item["action"] == "restored_previous":
batch._require_sha(
item["pre_apply_content_sha256"],
f"{label} restored content SHA-256",
)
if item["post_compensation_content_sha256"] != item["pre_apply_content_sha256"]:
raise ApplyPublicationError(f"{label} restored content hash drift")
return 1, 0, 0
if item["action"] == "removed_new":
if (
item["pre_apply_content_sha256"] is not None
or item["post_compensation_content_sha256"] is not None
):
raise ApplyPublicationError(f"{label} removal evidence drift")
return 0, 1, 0
if item["action"] == "unchanged_preexisting":
if unchanged_preexisting_sha256 is None:
raise ApplyPublicationError(f"{label} cannot be unchanged preexisting")
expected_sha256 = batch._require_sha(
unchanged_preexisting_sha256,
f"{label} expected preexisting content SHA-256",
)
if (
item["pre_apply_content_sha256"] != expected_sha256
or item["post_compensation_content_sha256"] != expected_sha256
):
raise ApplyPublicationError(f"{label} unchanged content hash drift")
return 0, 0, 1
raise ApplyPublicationError(f"{label} action is unsupported")
def _validate_rollback_response(
response: Any,
*,
manifest: Mapping[str, Any],
key: str,
transaction_id: str,
) -> dict[str, Any]:
row = _require_exact(
response,
"online rollback response",
(
"schema_version",
"idempotency_key",
"transaction_id",
"state",
"participant_states_before",
"participant_states_after",
"compensation_item_results",
"runtime_snapshot_compensation_results",
"restored_item_count",
"removed_item_count",
"unchanged_item_count",
"rollback_evidence_sha256",
),
)
if (
row["schema_version"] != ROLLBACK_RESPONSE_SCHEMA_VERSION
or row["idempotency_key"] != key
or row["transaction_id"] != transaction_id
or row["state"] != "rolled_back"
or not isinstance(row["restored_item_count"], int)
or isinstance(row["restored_item_count"], bool)
or row["restored_item_count"] < 0
or not isinstance(row["removed_item_count"], int)
or isinstance(row["removed_item_count"], bool)
or row["removed_item_count"] < 0
or not isinstance(row["unchanged_item_count"], int)
or isinstance(row["unchanged_item_count"], bool)
or row["unchanged_item_count"] < 0
):
raise ApplyPublicationError("online rollback evidence is invalid")
expected_participants = ["ai-platform", "contract-platform"]
before = row["participant_states_before"]
after = row["participant_states_after"]
if not isinstance(before, list) or not isinstance(after, list):
raise ApplyPublicationError("online rollback participant evidence is invalid")
validated_states: dict[str, dict[str, dict[str, Any]]] = {}
for label, states in (("before", before), ("after", after)):
if [item.get("participant") for item in states if isinstance(item, dict)] != expected_participants:
raise ApplyPublicationError(f"online rollback {label} participant identities drift")
validated_states[label] = {}
for index, value in enumerate(states):
state_row = _require_exact(
value,
f"online rollback {label} participant {index}",
(
"participant",
"state",
"write_count",
"runtime_snapshot_count",
"durable_state_sha256",
),
)
if (
not isinstance(state_row["state"], str)
or not isinstance(state_row["write_count"], int)
or isinstance(state_row["write_count"], bool)
or state_row["write_count"] < 0
or state_row["write_count"] > 74
or not isinstance(state_row["runtime_snapshot_count"], int)
or isinstance(state_row["runtime_snapshot_count"], bool)
or state_row["runtime_snapshot_count"] < 0
or state_row["runtime_snapshot_count"] > 14
):
raise ApplyPublicationError(
f"online rollback {label} participant state drift"
)
supplied_state_sha = batch._require_sha(
state_row["durable_state_sha256"],
f"online rollback {label} participant state SHA-256",
)
if supplied_state_sha != batch._sha256_json(
{
key_name: child
for key_name, child in state_row.items()
if key_name != "durable_state_sha256"
}
):
raise ApplyPublicationError(
f"online rollback {label} participant durable state hash drift"
)
validated_states[label][state_row["participant"]] = state_row
ai_before = validated_states["before"]["ai-platform"]
contract_before = validated_states["before"]["contract-platform"]
ai_was_committed = ai_before["state"] == "committed"
if ai_was_committed:
if (
ai_before["write_count"] != 14
or ai_before["runtime_snapshot_count"] != 14
):
raise ApplyPublicationError(
"online rollback AI committed state must contain exact 14+14 counts"
)
elif (
ai_before["state"] not in {"not_started", "prepared"}
or ai_before["write_count"] != 0
or ai_before["runtime_snapshot_count"] != 0
):
raise ApplyPublicationError("online rollback AI before state is not compensatable")
if (
contract_before["state"] not in {"not_started", "prepared"}
or contract_before["write_count"] != 0
or contract_before["runtime_snapshot_count"] != 0
):
raise ApplyPublicationError(
"online rollback Contract before state crossed the irreversible boundary"
)
expected_after = {
"ai-platform": "compensated_and_verified" if ai_was_committed else "unchanged",
"contract-platform": "unchanged",
}
for participant, expected_state in expected_after.items():
state_row = validated_states["after"][participant]
if (
state_row["state"] != expected_state
or state_row["write_count"] != 0
or state_row["runtime_snapshot_count"] != 0
):
raise ApplyPublicationError(
f"online rollback {participant} after state is not exact"
)
item_results = row["compensation_item_results"]
if not isinstance(item_results, list):
raise ApplyPublicationError("online rollback item results are invalid")
expected_identities = sorted(
(item["kind"], item["item_id"])
for item in batch._expected_apply_item_results(manifest)
if item["kind"] == "prompt_module"
)
supplied_identities: list[tuple[str, str]] = []
restored_count = 0
removed_count = 0
unchanged_count = 0
for index, value in enumerate(item_results):
item = _require_exact(
value,
f"online rollback item {index}",
(
"kind",
"item_id",
"pre_apply_content_sha256",
"post_compensation_content_sha256",
"action",
"status",
),
)
identity = (item["kind"], item["item_id"])
supplied_identities.append(identity)
restored, removed, unchanged = _validate_compensation_hashes(
item, f"online rollback item {index}"
)
restored_count += restored
removed_count += removed
unchanged_count += unchanged
required_publication_identities = expected_identities if ai_was_committed else []
if supplied_identities != required_publication_identities:
raise ApplyPublicationError(
"online rollback Prompt compensation identities/order drift"
)
runtime_results = row["runtime_snapshot_compensation_results"]
if not isinstance(runtime_results, list):
raise ApplyPublicationError(
"online rollback runtime snapshot results are invalid"
)
runtime_expectations = {
(item["kind"], item["runtime_key"], item["version"]): item
for item in expected_runtime_snapshot_results(manifest)
}
expected_runtime_identities = sorted(runtime_expectations)
supplied_runtime_identities: list[tuple[str, str, str]] = []
for index, value in enumerate(runtime_results):
item = _require_exact(
value,
f"online rollback runtime snapshot item {index}",
(
"kind",
"runtime_key",
"version",
"pre_apply_content_sha256",
"post_compensation_content_sha256",
"action",
"status",
),
)
identity = (item["kind"], item["runtime_key"], item["version"])
supplied_runtime_identities.append(identity)
expected_runtime = runtime_expectations.get(identity)
unchanged_sha256 = (
expected_runtime["expected_content_sha256"]
if expected_runtime is not None
and expected_runtime["kind"] == "existing_domain_prompt"
else None
)
restored, removed, unchanged = _validate_compensation_hashes(
item,
f"online rollback runtime snapshot item {index}",
unchanged_preexisting_sha256=unchanged_sha256,
)
if unchanged_sha256 is not None and item["action"] != "unchanged_preexisting":
raise ApplyPublicationError(
"online rollback preexisting runtime dependency was falsely compensated"
)
restored_count += restored
removed_count += removed
unchanged_count += unchanged
required_runtime_identities = expected_runtime_identities if ai_was_committed else []
if supplied_runtime_identities != required_runtime_identities:
raise ApplyPublicationError(
"online rollback runtime snapshot identities/order drift"
)
if (
restored_count != row["restored_item_count"]
or removed_count != row["removed_item_count"]
or unchanged_count != row["unchanged_item_count"]
):
raise ApplyPublicationError("online rollback item counts drift")
rollback_sha = batch._require_sha(
row["rollback_evidence_sha256"], "online rollback evidence SHA-256"
)
if rollback_sha != batch._sha256_json(
{
key_name: child
for key_name, child in row.items()
if key_name != "rollback_evidence_sha256"
}
):
raise ApplyPublicationError("online rollback evidence hash drift")
return row
def _compensate(
client: JsonHttpClient,
*,
manifest: Mapping[str, Any],
key: str,
transaction_id: str,
headers: Mapping[str, str],
manifest_raw_sha256: str,
approval_raw_sha256: str,
legal_review_binding_sha256: str,
environment_id: str,
tenant_id: str,
) -> dict[str, Any]:
request = {
"schema_version": ROLLBACK_REQUEST_SCHEMA_VERSION,
"idempotency_key": key,
"transaction_id": transaction_id,
"batch_manifest_raw_sha256": manifest_raw_sha256,
"approval_receipt_sha256": approval_raw_sha256,
"legal_source_review_binding_sha256": legal_review_binding_sha256,
"environment_id": environment_id,
"tenant_id": tenant_id,
"transaction_mode": batch.TRANSACTION_MODE,
"cross_database_atomicity": False,
}
response = client.request(
"POST",
f"/internal/rc06/publication-transactions/{transaction_id}/rollback",
payload=request,
headers=headers,
)
return _validate_rollback_response(
response,
manifest=manifest,
key=key,
transaction_id=transaction_id,
)
def _validate_execution_evidence(
evidence: Any,
*,
manifest: Mapping[str, Any],
manifest_raw_sha256: str,
approval: Mapping[str, Any],
approval_raw_sha256: str,
apply_service_public_key: Ed25519PublicKey,
online_service_public_key: Any,
legal_review_binding_sha256: str,
legal_review_expires_at: str,
environment_id: str,
tenant_id: str,
idempotency_key: str,
transaction_id: str,
) -> dict[str, Any]:
row = _require_exact(
evidence,
"online execution evidence",
(
"schema_version",
"idempotency_key",
"transaction_id",
"request_sha256",
"legal_source_review_binding_sha256",
"legal_source_review_expires_at",
"environment_id",
"tenant_id",
"transaction_mode",
"cross_database_atomicity",
"publication_item_count",
"runtime_snapshot_dependency_count",
"online_transaction_receipt",
"runtime_snapshot_receipt",
),
)
if (
row["schema_version"] != EXECUTION_EVIDENCE_SCHEMA_VERSION
or row["idempotency_key"] != idempotency_key
or row["transaction_id"] != transaction_id
or not batch.HEX64_RE.fullmatch(str(row["request_sha256"]))
or row["legal_source_review_binding_sha256"]
!= legal_review_binding_sha256
or row["legal_source_review_expires_at"] != legal_review_expires_at
or row["environment_id"] != environment_id
or row["tenant_id"] != tenant_id
or row["transaction_mode"] != batch.TRANSACTION_MODE
or row["cross_database_atomicity"] is not False
or row["publication_item_count"] != 74
or row["runtime_snapshot_dependency_count"] != 14
):
raise ApplyPublicationError("online execution evidence identity drift")
online_receipt = batch.validate_online_transaction_receipt(
manifest,
manifest_raw_sha256,
approval_raw_sha256,
approval,
apply_service_public_key,
online_service_public_key,
row["online_transaction_receipt"],
legal_review_binding_sha256=legal_review_binding_sha256,
legal_review_expires_at=legal_review_expires_at,
environment_id=environment_id,
tenant_id=tenant_id,
)
batch.validate_runtime_snapshot_receipt(
manifest,
manifest_raw_sha256,
approval_raw_sha256,
approval,
apply_service_public_key,
online_service_public_key,
online_receipt,
row["runtime_snapshot_receipt"],
legal_review_binding_sha256=legal_review_binding_sha256,
legal_review_expires_at=legal_review_expires_at,
environment_id=environment_id,
tenant_id=tenant_id,
)
return row
def _execution_from_transaction_status(
status: Mapping[str, Any],
*,
request_sha256: str,
legal_review_expires_at: str,
) -> dict[str, Any]:
if status["state"] not in {"committed_and_verified", "finalized"}:
raise ApplyPublicationError("online status does not contain committed execution evidence")
return {
"schema_version": EXECUTION_EVIDENCE_SCHEMA_VERSION,
"idempotency_key": status["idempotency_key"],
"transaction_id": status["transaction_id"],
"request_sha256": request_sha256,
"legal_source_review_binding_sha256": status[
"legal_source_review_binding_sha256"
],
"legal_source_review_expires_at": legal_review_expires_at,
"environment_id": status["environment_id"],
"tenant_id": status["tenant_id"],
"transaction_mode": status["transaction_mode"],
"cross_database_atomicity": status["cross_database_atomicity"],
"publication_item_count": status["publication_item_count"],
"runtime_snapshot_dependency_count": status[
"runtime_snapshot_dependency_count"
],
"online_transaction_receipt": status["online_transaction_receipt"],
"runtime_snapshot_receipt": status["runtime_snapshot_receipt"],
}
def _finalize_response_from_transaction_status(
status: Mapping[str, Any],
) -> dict[str, Any]:
if status["state"] != "finalized":
raise ApplyPublicationError("online status is not finalized")
return {
"schema_version": FINALIZE_RESPONSE_SCHEMA_VERSION,
"idempotency_key": status["idempotency_key"],
"transaction_id": status["transaction_id"],
"state": "finalized",
"no_go": False,
"apply_receipt_sha256": status["apply_receipt_sha256"],
"finalized_at": status["finalized_at"],
}
def _final_evidence_from_transaction_status(
execution: Mapping[str, Any],
status: Mapping[str, Any],
) -> dict[str, Any]:
return {
"schema_version": FINAL_EVIDENCE_SCHEMA_VERSION,
"transaction_mode": batch.TRANSACTION_MODE,
"cross_database_atomicity": False,
"publication_item_count": 74,
"runtime_snapshot_dependency_count": 14,
"online_execution": execution,
"apply_receipt": status["apply_receipt"],
"online_finalize_response": _finalize_response_from_transaction_status(status),
"online_finalize_status": status,
}
def execute_online_publication_batch(
*,
manifest: Mapping[str, Any],
manifest_raw_sha256: str,
approval: Mapping[str, Any],
approval_raw_sha256: str,
approval_keyring: Mapping[str, Any],
approval_keyring_raw_sha256: str,
approval_root_public_key: Ed25519PublicKey,
apply_service_public_key: Ed25519PublicKey,
online_service_public_key: Any,
legal_review_request: Mapping[str, Any],
legal_review_decision: Mapping[str, Any],
legal_review_keyring: Mapping[str, Any],
legal_review_keyring_raw_sha256: str,
authority_challenge: Mapping[str, Any],
environment_id: str,
tenant_id: str,
client: JsonHttpClient,
ledger: ApplyLedger,
now: datetime,
) -> dict[str, Any]:
"""Execute the online saga and persist evidence pending offline countersign."""
if now.tzinfo is None or now.utcoffset() is None:
raise ApplyPublicationError("online apply time must include a timezone")
checked_at = now.astimezone(UTC)
batch.validate_manifest(manifest)
if manifest["runtime_prompt_dependencies"]["items"] != batch._load_executable_prompt_dependencies(
REPO_ROOT
):
raise ApplyPublicationError(
"runtime Prompt name/version/content hashes differ from candidate executable source"
)
manifest_raw_sha256 = batch._require_sha(manifest_raw_sha256, "manifest raw SHA-256")
approval_raw_sha256 = batch._require_sha(approval_raw_sha256, "approval raw SHA-256")
approval_keyring_raw_sha256 = batch._require_sha(
approval_keyring_raw_sha256,
"approval keyring raw SHA-256",
)
approval_keyring_canonical_sha256 = batch._sha256_json(approval_keyring)
environment_id = _require_text(environment_id, "environment_id", maximum=256)
tenant_id = _require_text(tenant_id, "tenant_id", maximum=64)
batch.validate_approval_receipt(
manifest,
manifest_raw_sha256,
approval,
approval_keyring,
approval_root_public_key,
)
approval_approved_at = batch._parse_time(
approval["payload"]["approved_at"], "approval approved_at"
)
approval_expires_at = batch._parse_time(
approval["payload"]["expires_at"], "approval expires_at"
)
if checked_at < approval_approved_at or checked_at >= approval_expires_at:
raise ApplyPublicationError("approval is not currently valid for online apply")
legal_review_summary, legal_review_binding_sha256 = validate_scene_legal_review(
manifest,
approval,
legal_review_request,
legal_review_decision,
legal_review_keyring,
legal_review_keyring_raw_sha256,
now=now,
)
legal_review_expires_at = legal_review_summary["expires_at"]
keys = {
batch._public_key_spki(approval_root_public_key),
batch._public_key_spki(apply_service_public_key),
batch._public_key_spki(online_service_public_key),
}
if len(keys) != 3:
raise ApplyPublicationError("approval, apply and online service keys must be distinct")
key = _idempotency_key(
manifest_raw_sha256,
approval_raw_sha256,
legal_review_binding_sha256,
environment_id,
tenant_id,
)
transaction_id = _transaction_id(key)
validated_challenge = batch.validate_apply_challenge(
manifest,
manifest_raw_sha256,
approval_raw_sha256,
apply_service_public_key,
authority_challenge,
legal_review_binding_sha256=legal_review_binding_sha256,
legal_review_expires_at=legal_review_expires_at,
environment_id=environment_id,
tenant_id=tenant_id,
)
challenge_issued_at = batch._parse_time(
validated_challenge["payload"]["issued_at"], "apply challenge issued_at"
)
challenge_expires_at = batch._parse_time(
validated_challenge["payload"]["expires_at"], "apply challenge expires_at"
)
challenge_is_current = challenge_issued_at <= checked_at < challenge_expires_at
request_payload = {
"schema_version": APPLY_REQUEST_SCHEMA_VERSION,
"idempotency_key": key,
"transaction_id": transaction_id,
"environment_id": environment_id,
"tenant_id": tenant_id,
"transaction_mode": batch.TRANSACTION_MODE,
"cross_database_atomicity": False,
"batch_manifest_raw_sha256": manifest_raw_sha256,
"batch_manifest_payload_sha256": manifest["manifest_payload_sha256"],
"approval_receipt_sha256": approval_raw_sha256,
"approval_keyring": approval_keyring,
"approval_keyring_raw_sha256": approval_keyring_raw_sha256,
"approval_keyring_canonical_sha256": approval_keyring_canonical_sha256,
"legal_source_review_binding_sha256": legal_review_binding_sha256,
"legal_source_review_expires_at": legal_review_expires_at,
"authority_challenge": authority_challenge,
"manifest": manifest,
"approval_receipt": approval,
"legal_source_review_request": legal_review_request,
"legal_source_review_decision": legal_review_decision,
"legal_source_review_keyring": legal_review_keyring,
"legal_source_review_keyring_raw_sha256": legal_review_keyring_raw_sha256,
"expected_publication_item_results": batch._expected_apply_item_results(manifest),
"expected_publication_item_count": 74,
"expected_runtime_snapshot_dependencies": expected_runtime_snapshot_results(manifest),
"expected_runtime_snapshot_dependency_count": 14,
}
request_sha256 = batch._sha256_json(request_payload)
reservation, replay = ledger.reserve(
key,
request_sha256,
now,
initial_dispatch_authorized=challenge_is_current,
)
if replay is not None:
if replay.get("schema_version") == FINAL_EVIDENCE_SCHEMA_VERSION:
replay = replay.get("online_execution")
return _validate_execution_evidence(
replay,
manifest=manifest,
manifest_raw_sha256=manifest_raw_sha256,
approval=approval,
approval_raw_sha256=approval_raw_sha256,
apply_service_public_key=apply_service_public_key,
online_service_public_key=online_service_public_key,
legal_review_binding_sha256=legal_review_binding_sha256,
legal_review_expires_at=legal_review_expires_at,
environment_id=environment_id,
tenant_id=tenant_id,
idempotency_key=key,
transaction_id=transaction_id,
)
headers = _headers(
key,
manifest_raw_sha256,
approval_raw_sha256,
legal_review_binding_sha256,
tenant_id,
)
def validate_remote_status(
value: Any,
*,
minimum_state_version: int = 1,
expected_apply_receipt: Mapping[str, Any] | None = None,
) -> dict[str, Any]:
return _validate_transaction_status(
value,
manifest=manifest,
manifest_raw_sha256=manifest_raw_sha256,
approval=approval,
approval_raw_sha256=approval_raw_sha256,
approval_keyring=approval_keyring,
approval_root_public_key=approval_root_public_key,
apply_service_public_key=apply_service_public_key,
online_service_public_key=online_service_public_key,
request_sha256=request_sha256,
key=key,
transaction_id=transaction_id,
legal_review_binding_sha256=legal_review_binding_sha256,
legal_review_expires_at=legal_review_expires_at,
environment_id=environment_id,
tenant_id=tenant_id,
minimum_state_version=minimum_state_version,
expected_apply_receipt=expected_apply_receipt,
)
def adopt_committed_status(status_row: Mapping[str, Any]) -> dict[str, Any]:
execution = _execution_from_transaction_status(
status_row,
request_sha256=request_sha256,
legal_review_expires_at=legal_review_expires_at,
)
execution = _validate_execution_evidence(
execution,
manifest=manifest,
manifest_raw_sha256=manifest_raw_sha256,
approval=approval,
approval_raw_sha256=approval_raw_sha256,
apply_service_public_key=apply_service_public_key,
online_service_public_key=online_service_public_key,
legal_review_binding_sha256=legal_review_binding_sha256,
legal_review_expires_at=legal_review_expires_at,
environment_id=environment_id,
tenant_id=tenant_id,
idempotency_key=key,
transaction_id=transaction_id,
)
if status_row["state"] == "finalized":
final_evidence = _final_evidence_from_transaction_status(execution, status_row)
ledger.state(key, "succeeded", status_row, now, receipt=final_evidence)
else:
ledger.state(
key,
"online_committed_pending_countersign",
status_row,
now,
receipt=execution,
)
return execution
if reservation in {"probe", "recover"} and not challenge_is_current:
try:
reconciliation = client.request(
"GET",
f"/internal/rc06/publication-transactions/{transaction_id}/status",
payload=None,
headers=headers,
)
reconciliation = validate_remote_status(reconciliation)
except Exception as exc:
ledger.state(
key,
"commit_status_unknown",
{"reconciliation_error": str(exc)},
now,
error="expired challenge recovery could not establish remote commit status",
)
raise ApplyPublicationError(
"apply challenge is not currently valid for an initial dispatch and no existing transaction was proven"
) from exc
remote_state = reconciliation["state"]
if remote_state in {"committed_and_verified", "finalized"}:
return adopt_committed_status(reconciliation)
if remote_state == "rolled_back":
ledger.state(key, "rolled_back", reconciliation, now)
raise ApplyPublicationError("online apply was already rolled back")
if remote_state == "prepared":
ledger.state(
key,
"expired_challenge_recovery_no_go",
reconciliation,
now,
error="remote transaction was not terminally committed before challenge expiry",
)
raise ApplyPublicationError(
"expired challenge cannot authorize a new or non-terminal retransmission"
)
# irreversible_failure proves that this exact request already crossed
# the no-rollback boundary. Replaying it may only recover its evidence.
if remote_state != "irreversible_failure":
raise ApplyPublicationError("online transaction state is unsupported")
dispatch_started = False
response: Any = None
try:
dispatch_started = True
response = client.request(
"POST",
"/internal/rc06/publication-transactions/apply",
payload=request_payload,
headers={**headers, "X-RC06-Request-SHA256": request_sha256},
)
response = _validate_apply_response(
response,
key=key,
request_sha256=request_sha256,
legal_review_binding_sha256=legal_review_binding_sha256,
legal_review_expires_at=legal_review_expires_at,
transaction_id=transaction_id,
environment_id=environment_id,
tenant_id=tenant_id,
)
online_receipt = response["online_transaction_receipt"]
runtime_receipt = response["runtime_snapshot_receipt"]
batch.validate_online_transaction_receipt(
manifest,
manifest_raw_sha256,
approval_raw_sha256,
approval,
apply_service_public_key,
online_service_public_key,
online_receipt,
legal_review_binding_sha256=legal_review_binding_sha256,
legal_review_expires_at=legal_review_expires_at,
environment_id=environment_id,
tenant_id=tenant_id,
)
validate_runtime_snapshot_receipt(
manifest,
manifest_raw_sha256,
approval,
approval_raw_sha256,
legal_review_binding_sha256,
legal_review_expires_at,
apply_service_public_key,
online_service_public_key,
online_receipt,
runtime_receipt,
environment_id=environment_id,
tenant_id=tenant_id,
)
online_payload = online_receipt["payload"]
if online_payload["transaction_id"] != transaction_id:
raise ApplyPublicationError("signed apply receipt is not bound to the idempotency identity")
ledger.state(key, "verifying", response, now)
status = client.request(
"GET",
f"/internal/rc06/publication-transactions/{transaction_id}/status",
payload=None,
headers=headers,
)
status = validate_remote_status(status, minimum_state_version=3)
if status["state"] not in {"committed_and_verified", "finalized"}:
raise ApplyPublicationError("online apply did not reach a committed status")
if (
status["online_transaction_receipt"] != online_receipt
or status["runtime_snapshot_receipt"] != runtime_receipt
):
raise ApplyPublicationError("online apply response and durable status receipt drift")
return adopt_committed_status(status)
except Exception as exc:
if not isinstance(exc, ApplyPublicationError):
failure = ApplyPublicationError("unexpected online apply failure")
failure.__cause__ = exc
else:
failure = exc
if dispatch_started:
try:
reconciliation = client.request(
"GET",
f"/internal/rc06/publication-transactions/{transaction_id}/status",
payload=None,
headers=headers,
)
reconciliation = validate_remote_status(reconciliation)
except Exception as reconciliation_exc:
ledger.state(
key,
"commit_status_unknown",
{
"apply_error": str(failure),
"reconciliation_error": str(reconciliation_exc),
},
now,
error=f"{failure}; commit status is unknown",
)
raise ApplyPublicationError(
"online apply evidence failed and commit status is unknown; no rollback was attempted"
) from reconciliation_exc
remote_state = reconciliation["state"]
if remote_state in {"committed_and_verified", "finalized"}:
return adopt_committed_status(reconciliation)
if remote_state == "irreversible_failure":
ledger.state(
key,
"irreversible_failure_no_go",
reconciliation,
now,
error=str(failure),
)
raise ApplyPublicationError(
"online saga crossed the irreversible boundary but evidence recovery is incomplete; rollback is forbidden"
) from failure
if remote_state == "rolled_back":
ledger.state(key, "rolled_back", reconciliation, now, error=str(failure))
raise failure
if remote_state != "prepared":
ledger.state(
key,
"commit_status_unknown",
reconciliation,
now,
error=str(failure),
)
raise ApplyPublicationError(
"online saga state is not safely compensatable; no rollback was attempted"
) from failure
try:
rollback = _compensate(
client,
manifest=manifest,
key=key,
transaction_id=transaction_id,
headers=headers,
manifest_raw_sha256=manifest_raw_sha256,
approval_raw_sha256=approval_raw_sha256,
legal_review_binding_sha256=legal_review_binding_sha256,
environment_id=environment_id,
tenant_id=tenant_id,
)
ledger.state(key, "rolled_back", rollback, now, error=str(failure))
except Exception as rollback_exc:
ledger.state(
key,
"compensation_failed",
{"apply_error": str(failure), "rollback_error": str(rollback_exc)},
now,
error=f"{failure}; compensation failed: {rollback_exc}",
)
raise ApplyPublicationError(
"online apply failed and compensation could not be proven"
) from rollback_exc
else:
ledger.state(key, "failed", {"error": str(failure)}, now, error=str(failure))
raise failure
def finalize_publication_batch(
*,
manifest: Mapping[str, Any],
manifest_raw_sha256: str,
approval: Mapping[str, Any],
approval_raw_sha256: str,
approval_keyring: Mapping[str, Any],
approval_root_public_key: Ed25519PublicKey,
apply_service_public_key: Ed25519PublicKey,
online_service_public_key: Any,
legal_review_binding_sha256: str,
legal_review_expires_at: str,
environment_id: str,
tenant_id: str,
online_execution: Mapping[str, Any],
apply_receipt: Mapping[str, Any],
client: JsonHttpClient,
ledger: ApplyLedger,
now: datetime,
) -> dict[str, Any]:
"""Verify the offline countersign and move the local ledger to final success."""
key = batch.publication_idempotency_key(
manifest_raw_sha256,
approval_raw_sha256,
legal_review_binding_sha256,
environment_id,
tenant_id,
)
transaction_id = batch.publication_transaction_id(key)
execution = _validate_execution_evidence(
online_execution,
manifest=manifest,
manifest_raw_sha256=manifest_raw_sha256,
approval=approval,
approval_raw_sha256=approval_raw_sha256,
apply_service_public_key=apply_service_public_key,
online_service_public_key=online_service_public_key,
legal_review_binding_sha256=legal_review_binding_sha256,
legal_review_expires_at=legal_review_expires_at,
environment_id=environment_id,
tenant_id=tenant_id,
idempotency_key=key,
transaction_id=transaction_id,
)
batch.validate_apply_receipt(
manifest,
manifest_raw_sha256,
approval,
approval_keyring,
approval_root_public_key,
apply_service_public_key,
online_service_public_key,
approval_raw_sha256,
apply_receipt,
legal_review_binding_sha256=legal_review_binding_sha256,
legal_review_expires_at=legal_review_expires_at,
environment_id=environment_id,
tenant_id=tenant_id,
)
if (
apply_receipt["payload"]["online_transaction_receipt"]
!= execution["online_transaction_receipt"]
or apply_receipt["payload"]["runtime_snapshot_receipt"]
!= execution["runtime_snapshot_receipt"]
):
raise ApplyPublicationError("offline countersign is not bound to this receipt pair")
apply_receipt_sha256 = batch._sha256_json(apply_receipt)
state, stored = ledger.load(key, execution["request_sha256"])
if state not in {
"online_committed_pending_countersign",
"finalize_failed_no_go",
"succeeded",
}:
raise ApplyPublicationError("online saga is not eligible for offline finalization")
def validate_remote_status(value: Any, *, minimum_state_version: int) -> dict[str, Any]:
return _validate_transaction_status(
value,
manifest=manifest,
manifest_raw_sha256=manifest_raw_sha256,
approval=approval,
approval_raw_sha256=approval_raw_sha256,
approval_keyring=approval_keyring,
approval_root_public_key=approval_root_public_key,
apply_service_public_key=apply_service_public_key,
online_service_public_key=online_service_public_key,
request_sha256=execution["request_sha256"],
key=key,
transaction_id=transaction_id,
legal_review_binding_sha256=legal_review_binding_sha256,
legal_review_expires_at=legal_review_expires_at,
environment_id=environment_id,
tenant_id=tenant_id,
minimum_state_version=minimum_state_version,
expected_apply_receipt=apply_receipt,
)
if state == "succeeded":
stored_final = _require_exact(
stored,
"stored finalized evidence",
(
"schema_version",
"transaction_mode",
"cross_database_atomicity",
"publication_item_count",
"runtime_snapshot_dependency_count",
"online_execution",
"apply_receipt",
"online_finalize_response",
"online_finalize_status",
),
)
if (
stored_final["schema_version"] != FINAL_EVIDENCE_SCHEMA_VERSION
or stored_final["online_execution"] != execution
or stored_final["apply_receipt"] != apply_receipt
):
raise ApplyPublicationError("stored finalized evidence differs from the exact replay")
stored_status = validate_remote_status(
stored_final["online_finalize_status"], minimum_state_version=4
)
if stored_final != _final_evidence_from_transaction_status(execution, stored_status):
raise ApplyPublicationError("stored finalized evidence is internally inconsistent")
return stored_final
if stored != execution:
raise ApplyPublicationError("supplied online evidence differs from the durable ledger")
finalize_request = {
"schema_version": FINALIZE_REQUEST_SCHEMA_VERSION,
"idempotency_key": key,
"transaction_id": transaction_id,
"environment_id": environment_id,
"tenant_id": tenant_id,
"batch_manifest_raw_sha256": manifest_raw_sha256,
"approval_receipt_sha256": approval_raw_sha256,
"legal_source_review_binding_sha256": legal_review_binding_sha256,
"online_transaction_receipt_sha256": batch._sha256_json(
execution["online_transaction_receipt"]
),
"runtime_snapshot_receipt_sha256": batch._sha256_json(
execution["runtime_snapshot_receipt"]
),
"apply_receipt_sha256": apply_receipt_sha256,
"apply_receipt": apply_receipt,
}
headers = _headers(
key,
manifest_raw_sha256,
approval_raw_sha256,
legal_review_binding_sha256,
tenant_id,
)
response_row: dict[str, Any] | None = None
try:
response = client.request(
"POST",
f"/internal/rc06/publication-transactions/{transaction_id}/finalize",
payload=finalize_request,
headers={
**headers,
"X-RC06-Request-SHA256": batch._sha256_json(finalize_request),
},
)
response_row = _require_exact(
response,
"online finalize response",
(
"schema_version",
"idempotency_key",
"transaction_id",
"state",
"no_go",
"apply_receipt_sha256",
"finalized_at",
),
)
if (
response_row["schema_version"] != FINALIZE_RESPONSE_SCHEMA_VERSION
or response_row["idempotency_key"] != key
or response_row["transaction_id"] != transaction_id
or response_row["state"] != "finalized"
or response_row["no_go"] is not False
or response_row["apply_receipt_sha256"] != apply_receipt_sha256
):
raise ApplyPublicationError("online finalize response identity drift")
finalized_at = batch._parse_time(
response_row["finalized_at"], "online finalized_at"
)
if finalized_at < batch._parse_time(
apply_receipt["payload"]["countersigned_at"], "apply countersigned_at"
):
raise ApplyPublicationError("online finalize predates the offline countersign")
status = client.request(
"GET",
f"/internal/rc06/publication-transactions/{transaction_id}/status",
payload=None,
headers=headers,
)
status_row = validate_remote_status(status, minimum_state_version=4)
if status_row["state"] != "finalized":
raise ApplyPublicationError("online finalize did not reach finalized status")
if response_row != _finalize_response_from_transaction_status(status_row):
raise ApplyPublicationError("online finalize response and durable status drift")
except Exception as exc:
failure = (
exc
if isinstance(exc, ApplyPublicationError)
else ApplyPublicationError("online finalize request failed")
)
try:
reconciliation = client.request(
"GET",
f"/internal/rc06/publication-transactions/{transaction_id}/status",
payload=None,
headers=headers,
)
reconciliation = validate_remote_status(
reconciliation, minimum_state_version=3
)
if reconciliation["state"] == "finalized":
final_evidence = _final_evidence_from_transaction_status(
execution, reconciliation
)
ledger.state(
key, "succeeded", reconciliation, now, receipt=final_evidence
)
return final_evidence
if reconciliation["state"] != "committed_and_verified":
raise ApplyPublicationError(
"online finalization reconciliation regressed from committed state"
)
except Exception as reconciliation_exc:
ledger.state(
key,
"finalize_failed_no_go",
{
"finalize_error": str(failure),
"reconciliation_error": str(reconciliation_exc),
},
now,
receipt=execution,
error=f"{failure}; finalization status is untrusted",
)
raise failure from reconciliation_exc
ledger.state(
key,
"finalize_failed_no_go",
{"finalize_error": str(failure), "status": reconciliation},
now,
receipt=execution,
error=str(failure),
)
raise failure
final_evidence = _final_evidence_from_transaction_status(execution, status_row)
ledger.state(key, "succeeded", final_evidence, now, receipt=final_evidence)
return final_evidence
# Backward-compatible import name with deliberately changed two-stage semantics:
# it executes online only and never fabricates an offline authority receipt.
apply_publication_batch = execute_online_publication_batch
def _read_public_key(path: Path, expected_sha256: str, label: str) -> Ed25519PublicKey:
return batch._read_pinned_raw_public_key(
path,
expected_sha256=expected_sha256,
label=label,
)
def _read_online_public_key(path: Path) -> Any:
return batch._read_pinned_spki_public_key(
path,
expected_sha256=batch.TRUSTED_ONLINE_APPLY_SERVICE_PUBLIC_KEY_SPKI_SHA256,
label="online service public key",
)
def _outside_repo(path: Path, label: str) -> Path:
resolved = path.resolve()
try:
resolved.relative_to(REPO_ROOT)
except ValueError:
return resolved
raise ApplyPublicationError(f"{label} must be stored outside the source worktree")
def _write_receipt(
path: Path,
receipt: Mapping[str, Any],
*,
canonical_only: bool = False,
) -> str:
raw = batch._canonical(receipt) + (b"" if canonical_only else b"\n")
path.parent.mkdir(parents=True, exist_ok=True)
if path.exists():
existing = path.read_bytes()
if existing != raw:
raise ApplyPublicationError("refusing to overwrite different online apply evidence")
return _sha256(existing)
temporary = path.with_name(path.name + f".tmp-{os.getpid()}")
try:
with temporary.open("xb") as handle:
handle.write(raw)
handle.flush()
os.fsync(handle.fileno())
os.replace(temporary, path)
try:
path.chmod(0o600)
except OSError:
pass
finally:
if temporary.exists():
temporary.unlink()
return _sha256(raw)
def _add_common_arguments(parser: argparse.ArgumentParser) -> None:
parser.add_argument("--manifest", type=Path, required=True)
parser.add_argument("--manifest-sha256", required=True)
parser.add_argument("--approval", type=Path, required=True)
parser.add_argument("--approval-sha256", required=True)
parser.add_argument("--approval-keyring", type=Path, required=True)
parser.add_argument("--approval-keyring-sha256", required=True)
parser.add_argument("--approval-root-public-key", type=Path, required=True)
parser.add_argument("--apply-service-public-key", type=Path, required=True)
parser.add_argument("--online-service-public-key", type=Path, required=True)
parser.add_argument("--legal-review-request", type=Path, required=True)
parser.add_argument("--legal-review-request-sha256", required=True)
parser.add_argument("--legal-review-decision", type=Path, required=True)
parser.add_argument("--legal-review-decision-sha256", required=True)
parser.add_argument("--legal-review-keyring", type=Path, required=True)
parser.add_argument("--legal-review-keyring-sha256", required=True)
parser.add_argument("--environment-id", required=True)
parser.add_argument("--tenant-id", required=True)
parser.add_argument("--ledger", type=Path, required=True)
parser.add_argument("--output", type=Path, required=True)
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description=__doc__)
commands = parser.add_subparsers(dest="command", required=True)
execute = commands.add_parser(
"execute-online", help="execute and verify the online durable saga"
)
_add_common_arguments(execute)
execute.add_argument("--authority-challenge", type=Path, required=True)
execute.add_argument("--authority-challenge-sha256", required=True)
execute.add_argument("--service-url", required=True)
execute.add_argument("--online-receipt-output", type=Path, required=True)
execute.add_argument("--runtime-receipt-output", type=Path, required=True)
finalize = commands.add_parser(
"finalize", help="verify the offline countersign and finalize local evidence"
)
_add_common_arguments(finalize)
finalize.add_argument("--online-execution", type=Path, required=True)
finalize.add_argument("--online-execution-sha256", required=True)
finalize.add_argument("--apply-receipt", type=Path, required=True)
finalize.add_argument("--apply-receipt-sha256", required=True)
finalize.add_argument("--service-url", required=True)
args = parser.parse_args(argv)
ledger: ApplyLedger | None = None
try:
manifest, manifest_raw = batch.secure_read_json(
args.manifest, "publication manifest", args.manifest_sha256
)
approval, approval_raw = batch.secure_read_json(
args.approval, "approval receipt", args.approval_sha256
)
keyring, keyring_raw = batch.secure_read_json(
args.approval_keyring,
"approval keyring",
args.approval_keyring_sha256,
)
legal_request, _ = batch.secure_read_json(
args.legal_review_request,
"scene legal review request",
args.legal_review_request_sha256,
)
legal_decision, _ = batch.secure_read_json(
args.legal_review_decision,
"scene legal review decision",
args.legal_review_decision_sha256,
)
legal_keyring, legal_keyring_raw = batch.secure_read_json(
args.legal_review_keyring,
"scene legal review keyring",
args.legal_review_keyring_sha256,
)
root_key = _read_public_key(
args.approval_root_public_key,
batch.TRUSTED_APPROVAL_ROOT_PUBLIC_KEY_SHA256,
"approval root public key",
)
apply_key = _read_public_key(
args.apply_service_public_key,
batch.TRUSTED_APPLY_SERVICE_PUBLIC_KEY_SHA256,
"apply service public key",
)
online_key = _read_online_public_key(args.online_service_public_key)
ledger_path = _outside_repo(args.ledger, "apply ledger")
output_path = _outside_repo(args.output, "apply evidence")
ledger = ApplyLedger(ledger_path)
current = datetime.now(UTC)
legal_summary, legal_binding = validate_scene_legal_review(
manifest,
approval,
legal_request,
legal_decision,
legal_keyring,
legal_keyring_raw,
now=current,
)
if args.command == "execute-online":
token = os.environ.get(AUTH_TOKEN_ENV, "")
if not token:
raise ApplyPublicationError(f"{AUTH_TOKEN_ENV} is not set")
challenge, _ = batch.secure_read_json(
args.authority_challenge,
"apply authority challenge",
args.authority_challenge_sha256,
)
evidence = execute_online_publication_batch(
manifest=manifest,
manifest_raw_sha256=manifest_raw,
approval=approval,
approval_raw_sha256=approval_raw,
approval_keyring=keyring,
approval_keyring_raw_sha256=keyring_raw,
approval_root_public_key=root_key,
apply_service_public_key=apply_key,
online_service_public_key=online_key,
legal_review_request=legal_request,
legal_review_decision=legal_decision,
legal_review_keyring=legal_keyring,
legal_review_keyring_raw_sha256=legal_keyring_raw,
authority_challenge=challenge,
environment_id=args.environment_id,
tenant_id=args.tenant_id,
client=JsonHttpClient(args.service_url, token),
ledger=ledger,
now=current,
)
online_output = _outside_repo(
args.online_receipt_output, "online receipt"
)
runtime_output = _outside_repo(
args.runtime_receipt_output, "runtime receipt"
)
_write_receipt(
online_output,
evidence["online_transaction_receipt"],
canonical_only=True,
)
_write_receipt(
runtime_output,
evidence["runtime_snapshot_receipt"],
canonical_only=True,
)
status = "online_committed_pending_countersign"
else:
token = os.environ.get(AUTH_TOKEN_ENV, "")
if not token:
raise ApplyPublicationError(f"{AUTH_TOKEN_ENV} is not set")
online_execution, _ = batch.secure_read_json(
args.online_execution,
"online execution evidence",
args.online_execution_sha256,
)
apply_receipt, _ = batch.secure_read_json(
args.apply_receipt,
"offline apply receipt",
args.apply_receipt_sha256,
)
evidence = finalize_publication_batch(
manifest=manifest,
manifest_raw_sha256=manifest_raw,
approval=approval,
approval_raw_sha256=approval_raw,
approval_keyring=keyring,
approval_root_public_key=root_key,
apply_service_public_key=apply_key,
online_service_public_key=online_key,
legal_review_binding_sha256=legal_binding,
legal_review_expires_at=legal_summary["expires_at"],
environment_id=args.environment_id,
tenant_id=args.tenant_id,
online_execution=online_execution,
apply_receipt=apply_receipt,
client=JsonHttpClient(args.service_url, token),
ledger=ledger,
now=current,
)
status = "finalized_with_offline_countersign"
receipt_sha = _write_receipt(output_path, evidence)
print(
json.dumps(
{
"status": status,
"apply_evidence": str(output_path),
"apply_evidence_raw_sha256": receipt_sha,
"publication_item_count": 74,
"runtime_snapshot_dependency_count": 14,
},
ensure_ascii=False,
sort_keys=True,
)
)
return 0
except (batch.PublicationBatchError, OSError, sqlite3.Error) as exc:
print(f"rc06_apply_error: {exc}", file=sys.stderr)
return 2
finally:
if ledger is not None:
ledger.close()
if __name__ == "__main__":
raise SystemExit(main())