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

5227 lines
226 KiB
Python

#!/usr/bin/env python3
"""Prepare and verify the offline RC-06 asset and Prompt publication batch.
This tool is intentionally local-only. ``prepare`` writes one JSON artifact;
all validation commands are read-only and none of the commands call an HTTP
API, a database, a model provider, or a publication endpoint.
"""
from __future__ import annotations
import argparse
import base64
import csv
import hashlib
import importlib.util
import json
import os
import re
import stat
import subprocess
import sys
import tempfile
from datetime import UTC, datetime, timedelta
from pathlib import Path, PurePath
from typing import Any, Iterable, Mapping
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import ec, padding, rsa, utils
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
SCHEMA_VERSION = "yuqei.rc06-publication-batch.v4"
DISPOSITION_SCHEMA_VERSION = "yuqei.rc06-golden-dispositions.v2"
IMAGE_SCHEMA_VERSION = "yuqei.rc06-image-identities.v1"
APPROVAL_SCHEMA_VERSION = "yuqei.rc06-publication-batch-approval.v5"
APPROVAL_PAYLOAD_SCHEMA_VERSION = "yuqei.rc06-publication-batch-approval-payload.v4"
APPROVAL_REVIEW_SUMMARY_SCHEMA_VERSION = "yuqei.rc06-single-reviewer-summary.v2"
APPROVAL_KEYRING_SCHEMA_VERSION = "yuqei.rc06-publication-approval-keyring.v4"
APPLY_SCHEMA_VERSION = "yuqei.rc06-publication-system-item-apply-receipt.v6"
APPLY_PAYLOAD_SCHEMA_VERSION = "yuqei.rc06-publication-system-item-apply-payload.v4"
ONLINE_TRANSACTION_RECEIPT_SCHEMA_VERSION = "yuqei.rc06-online-transaction-receipt.v5"
ONLINE_TRANSACTION_PAYLOAD_SCHEMA_VERSION = "yuqei.rc06-online-transaction-payload.v4"
RUNTIME_RECEIPT_SCHEMA_VERSION = "yuqei.rc06-runtime-snapshot-receipt.v3"
RUNTIME_PAYLOAD_SCHEMA_VERSION = "yuqei.rc06-runtime-snapshot-payload.v2"
KMS_REQUEST_ID_ATTESTATION_SCHEMA_VERSION = "yuqei.rc06-kms-request-id-attestation.v1"
KMS_REQUEST_ID_ATTESTATION_PAYLOAD_SCHEMA_VERSION = (
"yuqei.rc06-kms-request-id-attestation-payload.v1"
)
APPLY_CHALLENGE_SCHEMA_VERSION = "yuqei.rc06-apply-challenge.v2"
APPLY_CHALLENGE_PAYLOAD_SCHEMA_VERSION = "yuqei.rc06-apply-challenge-payload.v2"
APPROVAL_SIGNATURE_DOMAIN = b"YUQEI_RC06_PUBLICATION_BATCH_APPROVAL_V1\0"
APPROVAL_KEYRING_SIGNATURE_DOMAIN = b"YUQEI_RC06_APPROVAL_KEYRING_V1\0"
APPLY_SIGNATURE_DOMAIN = b"YUQEI_RC06_SYSTEM_APPLY_RECEIPT_V2\0"
ONLINE_TRANSACTION_SIGNATURE_DOMAIN = b"YUQEI_RC06_ONLINE_TRANSACTION_RECEIPT_V2\0"
RUNTIME_SIGNATURE_DOMAIN = b"YUQEI_RC06_RUNTIME_SNAPSHOT_RECEIPT_V2\0"
ONLINE_REQUEST_ID_ATTESTATION_DOMAIN = (
b"YUQEI_RC06_ONLINE_TRANSACTION_REQUEST_ID_ATTESTATION_V1\0"
)
RUNTIME_REQUEST_ID_ATTESTATION_DOMAIN = (
b"YUQEI_RC06_RUNTIME_SNAPSHOT_REQUEST_ID_ATTESTATION_V1\0"
)
APPLY_CHALLENGE_SIGNATURE_DOMAIN = b"YUQEI_RC06_APPLY_CHALLENGE_V2\0"
APPLY_OPERATION = "apply_rc06_publication_batch"
TRANSACTION_MODE = "durable_saga"
MAX_APPLY_CHALLENGE_TTL = timedelta(minutes=10)
TRUSTED_APPROVAL_ROOT_KEY_ID = "yuqei-rc06-approval-root-v1"
# Provision the long-lived root/apply pins and exact candidate keyring epoch
# before source freeze. A root-signed keyring then authorizes the exact frozen
# manifest raw SHA without creating a source/keyring hash cycle. Rotation or
# revocation requires a new epoch and therefore a new frozen candidate.
TRUSTED_APPROVAL_ROOT_PUBLIC_KEY_SHA256 = ""
FROZEN_APPROVAL_KEYRING_EPOCH = 0
TRUSTED_APPLY_SERVICE_PUBLIC_KEY_SHA256 = ""
# These values must be provisioned from the real publication service before
# source freeze. Empty defaults deliberately make every formal apply receipt
# fail closed; a caller-provided environment name or key cannot override them.
TRUSTED_ONLINE_APPLY_SERVICE_PROVIDER = ""
TRUSTED_ONLINE_APPLY_SERVICE_KEY_REFERENCE = ""
TRUSTED_ONLINE_APPLY_SERVICE_KEY_VERSION = ""
TRUSTED_ONLINE_APPLY_SERVICE_ALGORITHM = ""
TRUSTED_ONLINE_APPLY_SERVICE_PUBLIC_KEY_SPKI_SHA256 = ""
TRUSTED_ONLINE_APPLY_SERVICE_COMPONENT = "rc06-publication-service"
TRUSTED_ONLINE_APPLY_ENVIRONMENT_IDS: tuple[str, ...] = ()
# Pin the exact canonical legal-review keyring bytes before candidate freeze.
# Empty deliberately rejects caller-supplied/self-signed reviewer keyrings.
TRUSTED_SCENE_LEGAL_REVIEW_KEYRING_SHA256 = ""
RC05_SUMMARY_SCHEMA_VERSION = "multiscene-evaluation-run.v1"
RC05_PLAN_SCHEMA_VERSION = "multiscene-evaluation-plan.v2"
RC05_CANDIDATE_SCHEMA_VERSION = "multiscene-candidate-binding.v1"
RC05_RELEASE_CONTROLS_SCHEMA_VERSION = "multiscene-release-controls.v2"
RC05_LEDGER_SCHEMA_VERSION = "multiscene-call-ledger.v2"
RC05_LEDGER_SNAPSHOT_SCHEMA_VERSION = "multiscene-call-ledger-snapshot.v2"
RC05_CAMPAIGN_SCHEMA_VERSION = "multiscene-call-campaign.v2"
RC05_CONTROL_STATE_SCHEMA_VERSION = "multiscene-release-control-state.v1"
EXPECTED_RC05_CANARY_CASE_IDS = (
"base--TPL-AGENCY-DISTRIBUTION-001--normal",
"base--TPL-DEMAND-LETTER-001--normal",
"base--TPL-PURCHASE-GOODS-001--normal",
"scene--TPL-AMENDMENT-GENERAL-001--opposite-adversarial",
"specialist-trade_procurement-first",
"intake-tpl-purchase-goods-001",
)
# Each tuple entry is missing evidence, not a request for another human reviewer.
# Validation removes the first two entries as the single-reviewer approval and
# system-generated per-item apply evidence are supplied. Runtime Prompt snapshots
# remain a separate UAT gate.
BLOCKED_CONTROLS = (
"single_reviewer_batch_approval_receipt",
"system_generated_item_apply_receipts_and_online_snapshots",
"runtime_executable_prompt_snapshots_1_drafting_plus_13_review",
)
# Only the stable key owner identity is frozen in source. A title, organization,
# and authorization scope are human assertions for one exact approval and must
# be supplied and confirmed during the interactive signing ceremony.
SOLE_RELEASE_REVIEWER = {
"approver_id": "chen-yuqi",
"name": "陈钰麒",
}
RELEASE_REVIEWER_IDENTITY_FIELDS = (
"approver_id",
"name",
"role",
"organization",
"authorization_scope",
)
MAX_APPROVAL_WINDOW = timedelta(days=7)
RC05_HISTORICAL_ATTEMPT_KEYS = {
"attempt_id", "plan_sha256", "case_id", "operation",
"provider_status", "business_status", "elapsed_seconds", "timed_out",
"request_sha256", "response_sha256", "provider", "model",
"job_id", "audit_run_id", "identity_path", "identity_file_sha256",
"ledger_identity_sha256", "claim_path", "claim_sha256", "finish_path",
"finish_sha256", "before_path", "before_sha256", "after_path",
"after_sha256", "disposition",
}
EXPECTED_ASSET_COUNT = 60
EXPECTED_DRAFTING_MODULE_COUNT = 6
EXPECTED_REVIEW_MODULE_COUNT = 8
EXPECTED_MODULE_COUNT = EXPECTED_DRAFTING_MODULE_COUNT + EXPECTED_REVIEW_MODULE_COUNT
EXPECTED_DEFAULT_PROMPT_COUNT = 46
EXPECTED_RUNTIME_PROMPT_COUNT = 14
EXPECTED_GOLDEN_COUNT = 31
EXPECTED_GOLDEN_GENERATION_COUNT = 23
EXPECTED_GOLDEN_CLAUSE_COUNT = 8
EXPECTED_RC05_OPERATION_LIMITS = {
"draft": 120,
"semantic_review": 30,
"repair_draft": 8,
"repair_review": 8,
"specialist_review": 106,
"intake": 8,
}
REQUIRED_IMAGE_ROLES = (
"contract-web",
"contract-api",
"ai-platform-api",
"ai-worker",
)
HEX64_RE = re.compile(r"[0-9a-f]{64}")
COMMIT_RE = re.compile(r"(?:[0-9a-f]{40}|[0-9a-f]{64})")
TAG_RE = re.compile(r"[A-Za-z0-9][A-Za-z0-9._/-]{0,127}")
STABLE_ID_RE = re.compile(r"[A-Za-z0-9][A-Za-z0-9._-]{0,191}")
RFC3339_RE = re.compile(
r"[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}"
r"(?:\.[0-9]+)?(?:Z|[+-][0-9]{2}:[0-9]{2})"
)
ASSET_ROOT = (
"yuqei-contract-platform/services/contract-api/src/yuqei_contract_api/"
"template_assets/v1_contract_templates"
)
DRAFTING_MODULE_PATH = (
"yuqei-ai-platform/services/ai-platform-api/src/yuqei_ai_platform_api/"
"drafting_prompt_modules.json"
)
REVIEW_MODULE_PATH = (
"yuqei-ai-platform/services/ai-platform-api/src/yuqei_ai_platform_api/"
"review_scene_modules.json"
)
DEFAULT_PROMPT_PATH = (
"yuqei-ai-platform/services/ai-platform-api/src/yuqei_ai_platform_api/"
"prompt_assets/v1_phase15/default-prompt-assets.json"
)
RUNTIME_EXISTING_DOMAIN_PROMPTS = (
"contract_review_channel_franchise",
"contract_review_employment_hr",
"contract_review_investment_finance",
"contract_review_real_estate_property",
"contract_review_tech_saas_data_compliance",
)
DRAFTING_RUNTIME_MODULE_ORDER = (
"draft_intake",
"template_match",
"missing_facts_questions",
"clause_assembly_plan",
"draft_consistency_check",
"candidate_revision_explanation",
)
GOLDEN_INVENTORY_PATH = (
"yuqei-ai-platform/services/ai-platform-api/src/yuqei_ai_platform_api/"
"golden_assets/v1_phase13_legal_knowledge_template_library/inventories/"
"generation-golden-sample-inventory.csv"
)
FROZEN_IMPLEMENTATION_PATHS = (
"yuqei-infra/scripts/build-rc06-publication-batch.py",
"yuqei-infra/scripts/apply-rc06-publication-batch.py",
"yuqei-infra/scripts/build-scene-source-legal-review.py",
"yuqei-infra/scripts/rc06-single-reviewer-signing.py",
"yuqei-infra/scripts/rc06-release-trust-bootstrap.py",
"yuqei-contract-platform/services/contract-api/src/yuqei_contract_api/contract_templates.py",
"yuqei-contract-platform/services/contract-api/src/yuqei_contract_api/contract_scene_assets.py",
"yuqei-contract-platform/services/contract-api/src/yuqei_contract_api/template_inputs.py",
"yuqei-ai-sdk-python/src/yuqei_sdk/review_routing.py",
DRAFTING_MODULE_PATH,
REVIEW_MODULE_PATH,
DEFAULT_PROMPT_PATH,
GOLDEN_INVENTORY_PATH,
)
CONTRACT_RUNTIME_PACKAGE_ROOT = (
"yuqei-contract-platform/services/contract-api/src/yuqei_contract_api"
)
SDK_RUNTIME_PACKAGE_ROOT = "yuqei-ai-sdk-python/src/yuqei_sdk"
AI_RUNTIME_PACKAGE_ROOT = (
"yuqei-ai-platform/services/ai-platform-api/src/yuqei_ai_platform_api"
)
DISPOSITION_STATUSES = {
"named_legal_approval",
"scoped_internal_risk_acceptance",
"unresolved",
}
SECRET_KEYS = {
"api_key",
"apikey",
"authorization",
"client_secret",
"credential",
"credentials",
"password",
"private_key",
"secret",
"token",
}
SECRET_MARKERS = (
"-----BEGIN PRIVATE KEY-----",
"-----BEGIN RSA PRIVATE KEY-----",
"-----BEGIN OPENSSH PRIVATE KEY-----",
)
class PublicationBatchError(RuntimeError):
"""An RC-06 batch input or receipt is incomplete, unsafe, or inconsistent."""
def _reject_duplicate_json_pairs(pairs: list[tuple[str, Any]]) -> dict[str, Any]:
result: dict[str, Any] = {}
for key, value in pairs:
if key in result:
raise PublicationBatchError(f"duplicate JSON key is forbidden: {key}")
result[key] = value
return result
def _reject_json_constant(value: str) -> None:
raise PublicationBatchError(f"non-finite JSON value is forbidden: {value}")
def _canonical(value: Any) -> bytes:
try:
return json.dumps(
value,
ensure_ascii=False,
sort_keys=True,
separators=(",", ":"),
allow_nan=False,
).encode("utf-8")
except (TypeError, ValueError) as exc:
raise PublicationBatchError(f"value is not canonical JSON: {exc}") from exc
def _sha256_bytes(value: bytes) -> str:
return hashlib.sha256(value).hexdigest()
def _sha256_json(value: Any) -> str:
return _sha256_bytes(_canonical(value))
def _verify_embedded_hash(value: Mapping[str, Any], field: str, label: str) -> str:
digest = _require_sha(value.get(field), f"{label} {field}")
projection = {key: child for key, child in value.items() if key != field}
if _sha256_json(projection) != digest:
raise PublicationBatchError(f"{label} embedded hash drift")
return digest
def _require_sha(value: Any, label: str) -> str:
if not isinstance(value, str) or not HEX64_RE.fullmatch(value):
raise PublicationBatchError(f"{label} must be a lowercase SHA-256 hex digest")
return value
def _require_string(value: Any, label: str, *, max_length: int = 4096) -> str:
if not isinstance(value, str) or not value.strip() or len(value) > max_length:
raise PublicationBatchError(f"{label} must be a non-empty string")
return value.strip()
def _require_keys(
value: Any,
label: str,
required: Iterable[str],
optional: Iterable[str] = (),
) -> dict[str, Any]:
if not isinstance(value, dict):
raise PublicationBatchError(f"{label} must be an object")
required_set = set(required)
allowed = required_set | set(optional)
missing = sorted(required_set - set(value))
extra = sorted(set(value) - allowed)
if missing or extra:
raise PublicationBatchError(f"{label} keys invalid; missing={missing}, extra={extra}")
return value
def _parse_time(value: Any, label: str) -> datetime:
if not isinstance(value, str) or not RFC3339_RE.fullmatch(value):
raise PublicationBatchError(f"{label} must be an RFC3339 timestamp with timezone")
try:
parsed = datetime.fromisoformat(value.replace("Z", "+00:00"))
except ValueError as exc:
raise PublicationBatchError(f"{label} is not a valid timestamp") from exc
if parsed.tzinfo is None:
raise PublicationBatchError(f"{label} must include a timezone")
return parsed
def _require_count(value: Any, label: str, *, maximum: int | None = None) -> int:
if not isinstance(value, int) or isinstance(value, bool) or value < 0:
raise PublicationBatchError(f"{label} must be a non-negative integer")
if maximum is not None and value > maximum:
raise PublicationBatchError(f"{label} exceeds its frozen limit {maximum}")
return value
def _require_nonnegative_number(value: Any, label: str) -> float:
if (
not isinstance(value, (int, float))
or isinstance(value, bool)
or value < 0
or value != value
or value in {float("inf"), float("-inf")}
):
raise PublicationBatchError(f"{label} must be a finite non-negative number")
return float(value)
def _validate_elapsed_statistics(
value: Any,
label: str,
*,
expected_observed: int,
) -> None:
row = _require_keys(value, label, ("observed", "p50", "p95"))
observed = _require_count(row["observed"], f"{label}.observed")
if observed != expected_observed:
raise PublicationBatchError(f"{label}.observed does not match its call count")
if observed == 0:
if row["p50"] is not None or row["p95"] is not None:
raise PublicationBatchError(f"{label} percentiles must be null without observations")
return
p50 = _require_nonnegative_number(row["p50"], f"{label}.p50")
p95 = _require_nonnegative_number(row["p95"], f"{label}.p95")
if p50 > p95:
raise PublicationBatchError(f"{label} percentiles are not monotonic")
def _assert_no_secret_material(value: Any, label: str = "document") -> None:
if isinstance(value, dict):
for key, child in value.items():
normalized = str(key).strip().casefold().replace("-", "_")
if normalized in SECRET_KEYS:
raise PublicationBatchError(f"{label} contains forbidden secret field: {key}")
_assert_no_secret_material(child, f"{label}.{key}")
elif isinstance(value, list):
for index, child in enumerate(value):
_assert_no_secret_material(child, f"{label}[{index}]")
elif isinstance(value, str) and any(marker in value for marker in SECRET_MARKERS):
raise PublicationBatchError(f"{label} contains private-key material")
def _path_has_parent_traversal(path: Path) -> bool:
return any(part == ".." for part in PurePath(os.fspath(path)).parts)
def _assert_no_symlink_components(path: Path, label: str) -> None:
absolute = path.absolute()
parts = absolute.parts
if not parts:
raise PublicationBatchError(f"{label} is empty")
current = Path(parts[0])
for part in parts[1:]:
current = current / part
if not current.exists() and not current.is_symlink():
continue
try:
mode = current.lstat().st_mode
except OSError as exc:
raise PublicationBatchError(f"cannot inspect {label}: {exc}") from exc
file_attributes = getattr(current.lstat(), "st_file_attributes", 0)
reparse_flag = getattr(stat, "FILE_ATTRIBUTE_REPARSE_POINT", 0)
if stat.S_ISLNK(mode) or bool(reparse_flag and file_attributes & reparse_flag):
raise PublicationBatchError(f"{label} must not traverse a symbolic link: {current}")
def secure_read_bytes(path: Path, label: str, *, maximum_bytes: int = 128 * 1024 * 1024) -> bytes:
if _path_has_parent_traversal(path):
raise PublicationBatchError(f"{label} must not contain parent traversal")
_assert_no_symlink_components(path, label)
lexical = path.absolute()
flags = os.O_RDONLY | getattr(os, "O_BINARY", 0) | getattr(os, "O_NOFOLLOW", 0)
try:
descriptor = os.open(lexical, flags)
except OSError as exc:
raise PublicationBatchError(f"cannot open {label}: {exc}") from exc
try:
opened = os.fstat(descriptor)
named = os.lstat(lexical)
if (
not stat.S_ISREG(opened.st_mode)
or not stat.S_ISREG(named.st_mode)
or not os.path.samestat(opened, named)
):
raise PublicationBatchError(f"{label} must be a stable regular file")
if opened.st_size < 0 or opened.st_size > maximum_bytes:
raise PublicationBatchError(f"{label} exceeds the {maximum_bytes}-byte limit")
chunks: list[bytes] = []
remaining = opened.st_size
while remaining:
chunk = os.read(descriptor, min(1024 * 1024, remaining))
if not chunk:
raise PublicationBatchError(f"{label} changed while it was being read")
chunks.append(chunk)
remaining -= len(chunk)
if os.read(descriptor, 1):
raise PublicationBatchError(f"{label} changed while it was being read")
after = os.fstat(descriptor)
try:
named_after = os.lstat(lexical)
except OSError as exc:
raise PublicationBatchError(f"{label} changed while it was being read") from exc
if (
after.st_size != opened.st_size
or after.st_mtime_ns != opened.st_mtime_ns
or after.st_ctime_ns != opened.st_ctime_ns
or not os.path.samestat(after, named_after)
):
raise PublicationBatchError(f"{label} changed while it was being read")
return b"".join(chunks)
finally:
os.close(descriptor)
def secure_read_json(path: Path, label: str, expected_sha256: str | None = None) -> tuple[Any, str]:
raw = secure_read_bytes(path, label)
actual = _sha256_bytes(raw)
if expected_sha256 is not None and actual != _require_sha(expected_sha256, f"{label} expected SHA-256"):
raise PublicationBatchError(f"{label} raw SHA-256 mismatch")
try:
payload = json.loads(
raw,
object_pairs_hook=_reject_duplicate_json_pairs,
parse_constant=_reject_json_constant,
)
except PublicationBatchError:
raise
except (UnicodeDecodeError, json.JSONDecodeError) as exc:
raise PublicationBatchError(f"{label} is not valid UTF-8 JSON") from exc
return payload, actual
def _safe_output_path(path: Path) -> None:
if _path_has_parent_traversal(path):
raise PublicationBatchError("output path must not contain parent traversal")
if path.exists() or path.is_symlink():
raise PublicationBatchError("output already exists; refusing to overwrite immutable evidence")
_assert_no_symlink_components(path.parent, "output parent")
path.parent.mkdir(parents=True, exist_ok=True)
_assert_no_symlink_components(path.parent, "output parent")
def _run_git(repo: Path, *args: str, binary: bool = False) -> str | bytes:
completed = subprocess.run(
["git", "-c", f"safe.directory={repo.resolve()}", "-C", str(repo), *args],
check=False,
capture_output=True,
timeout=30,
env={
**{key: os.environ[key] for key in ("SYSTEMROOT", "WINDIR", "PATH") if key in os.environ},
"GIT_CONFIG_NOSYSTEM": "1",
"GIT_NO_REPLACE_OBJECTS": "1",
"GIT_OPTIONAL_LOCKS": "0",
"GIT_TERMINAL_PROMPT": "0",
"LANG": "C.UTF-8",
"LC_ALL": "C.UTF-8",
},
)
if completed.returncode:
message = completed.stderr.decode("utf-8", "replace").strip()
raise PublicationBatchError(f"git {' '.join(args)} failed: {message}")
return completed.stdout if binary else completed.stdout.decode("utf-8", "strict").strip()
def validate_candidate(repo: Path, commit: str, tag: str) -> None:
if not COMMIT_RE.fullmatch(commit):
raise PublicationBatchError("commit must be a full lowercase Git object id")
if not TAG_RE.fullmatch(tag) or ".." in tag or tag.endswith("/"):
raise PublicationBatchError("tag is invalid or ambiguous")
resolved_commit = str(_run_git(repo, "rev-parse", "--verify", f"{commit}^{{commit}}"))
if resolved_commit != commit:
raise PublicationBatchError("commit does not resolve exactly")
resolved_tag = str(_run_git(repo, "rev-parse", "--verify", f"refs/tags/{tag}^{{commit}}"))
if resolved_tag != commit:
raise PublicationBatchError("tag does not resolve to the requested commit")
def _relative_source_path(repo: Path, path: Path) -> str:
try:
relative = path.resolve(strict=True).relative_to(repo.resolve(strict=True))
except (OSError, ValueError) as exc:
raise PublicationBatchError(f"source escapes the repository: {path}") from exc
return relative.as_posix()
def _inventory_source_paths(repo: Path, commit: str | None = None) -> list[str]:
paths: list[str] = []
if commit is None:
asset_root = repo / ASSET_ROOT
_assert_no_symlink_components(asset_root, "template asset root")
if not asset_root.is_dir():
raise PublicationBatchError("template asset root is missing")
for path in asset_root.rglob("*"):
if path.is_symlink():
raise PublicationBatchError(f"template source must not be a symbolic link: {path}")
if path.is_file() and path.suffix.lower() in {".json", ".md"}:
paths.append(_relative_source_path(repo, path))
for package_root in (
CONTRACT_RUNTIME_PACKAGE_ROOT,
SDK_RUNTIME_PACKAGE_ROOT,
AI_RUNTIME_PACKAGE_ROOT,
):
root = repo / package_root
_assert_no_symlink_components(root, f"runtime package {package_root}")
paths.extend(
_relative_source_path(repo, path)
for path in root.rglob("*.py")
if path.is_file() and not path.is_symlink()
)
else:
listing = str(
_run_git(
repo,
"ls-tree",
"-r",
"--name-only",
commit,
"--",
ASSET_ROOT,
CONTRACT_RUNTIME_PACKAGE_ROOT,
SDK_RUNTIME_PACKAGE_ROOT,
AI_RUNTIME_PACKAGE_ROOT,
)
)
for relative in listing.splitlines():
# Freeze every tracked package resource, not only Python modules.
# Runtime code resolves template and other data files relative to
# ``__file__``; omitting those transitive inputs would allow the
# inventory to consume mutable worktree data after code validation.
if (
relative.startswith(f"{CONTRACT_RUNTIME_PACKAGE_ROOT}/")
or relative.startswith(f"{SDK_RUNTIME_PACKAGE_ROOT}/")
or relative.startswith(f"{AI_RUNTIME_PACKAGE_ROOT}/")
):
paths.append(relative)
paths.extend(FROZEN_IMPLEMENTATION_PATHS)
return sorted(set(paths))
def _source_manifest_index(payload: Any, commit: str) -> tuple[dict[str, str], str | None]:
manifest = _require_keys(
payload,
"source manifest",
("schema_version", "candidate", "files", "summaries", "claims_not_made", "manifest_payload_sha256"),
)
if manifest["schema_version"] != "yuqei.release-source-manifest.v1":
raise PublicationBatchError("unsupported source manifest schema")
_verify_embedded_hash(manifest, "manifest_payload_sha256", "source manifest")
candidate = _require_keys(
manifest["candidate"],
"source manifest candidate",
("commit", "commit_timestamp", "tree", "worktree_was_clean", "identity_policy"),
)
if candidate["commit"] != commit:
raise PublicationBatchError("source manifest commit does not match the batch")
if candidate["worktree_was_clean"] is not True:
raise PublicationBatchError("source manifest is not from a clean candidate")
files = _require_keys(
manifest["files"],
"source manifest files",
("count", "total_size", "content_index_sha256", "items"),
)
if not isinstance(files["items"], list):
raise PublicationBatchError("source manifest file inventory is missing")
if files["count"] != len(files["items"]):
raise PublicationBatchError("source manifest file count is inconsistent")
_require_sha(files["content_index_sha256"], "source manifest content index SHA-256")
index: dict[str, str] = {}
for number, item in enumerate(files["items"]):
row = _require_keys(
item,
f"source manifest file {number}",
("path", "mode", "git_blob_oid", "size", "sha256"),
)
path = row["path"]
digest = row["sha256"]
if not isinstance(path, str) or path.startswith(("/", "\\")) or ".." in PurePath(path).parts:
raise PublicationBatchError("source manifest contains an unsafe path")
_require_sha(digest, f"source manifest {path}")
if path in index:
raise PublicationBatchError(f"duplicate source manifest path: {path}")
index[path] = digest
return index, manifest["manifest_payload_sha256"]
def verify_frozen_sources(
repo: Path,
commit: str,
source_manifest: Any,
required_paths: Iterable[str],
) -> None:
index, _ = _source_manifest_index(source_manifest, commit)
for relative in required_paths:
if relative not in index:
raise PublicationBatchError(f"frozen source is absent from source manifest: {relative}")
path = repo / Path(relative)
working = secure_read_bytes(path, f"frozen source {relative}")
committed = bytes(_run_git(repo, "show", f"{commit}:{relative}", binary=True))
if _sha256_bytes(committed) != index[relative]:
raise PublicationBatchError(f"commit source differs from source manifest: {relative}")
# Windows may check a text file out with CRLF while the frozen blob is
# LF. Accept only that transparent transform; never accept other
# filtered or semantic changes.
checkout_equivalent = working == committed
if not checkout_equivalent and b"\0" not in working and b"\0" not in committed:
checkout_equivalent = working.replace(b"\r\n", b"\n") == committed.replace(b"\r\n", b"\n")
if not checkout_equivalent:
raise PublicationBatchError(f"working source differs from frozen commit: {relative}")
def _write_frozen_source(path: Path, raw: bytes, label: str) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
_assert_no_symlink_components(path.parent, f"{label} parent")
flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL | getattr(os, "O_BINARY", 0)
flags |= getattr(os, "O_NOFOLLOW", 0)
descriptor: int | None = None
try:
descriptor = os.open(path, flags, 0o600)
offset = 0
while offset < len(raw):
written = os.write(descriptor, raw[offset:])
if written <= 0:
raise PublicationBatchError(f"cannot stage complete {label}")
offset += written
os.fsync(descriptor)
except OSError as exc:
raise PublicationBatchError(f"cannot stage {label}: {exc}") from exc
finally:
if descriptor is not None:
os.close(descriptor)
if secure_read_bytes(path, label) != raw:
raise PublicationBatchError(f"staged {label} differs from the frozen Git object")
def stage_frozen_sources(
repo: Path,
commit: str,
source_manifest: Any,
required_paths: Iterable[str],
destination: Path,
) -> None:
"""Materialize verified Git-object bytes into a private, isolated source tree."""
index, _ = _source_manifest_index(source_manifest, commit)
destination.mkdir(mode=0o700, parents=True, exist_ok=False)
_assert_no_symlink_components(destination, "frozen staging root")
for relative in required_paths:
if relative not in index:
raise PublicationBatchError(f"frozen source is absent from source manifest: {relative}")
raw = bytes(_run_git(repo, "show", f"{commit}:{relative}", binary=True))
if _sha256_bytes(raw) != index[relative]:
raise PublicationBatchError(f"commit source differs from source manifest: {relative}")
_write_frozen_source(
destination / Path(relative),
raw,
f"frozen staged source {relative}",
)
def _project_imports(repo: Path) -> tuple[list[str], dict[str, Any]]:
paths = (
repo / "yuqei-contract-platform/services/contract-api/src",
repo / "yuqei-ai-sdk-python/src",
)
inserted: list[str] = []
for path in reversed(paths):
value = str(path)
if value not in sys.path:
sys.path.insert(0, value)
inserted.append(value)
prefixes = ("yuqei_contract_api", "yuqei_sdk")
previous = {
name: module
for name, module in list(sys.modules.items())
if name == prefixes[0]
or name.startswith(f"{prefixes[0]}.")
or name == prefixes[1]
or name.startswith(f"{prefixes[1]}.")
}
for name in previous:
sys.modules.pop(name, None)
return inserted, previous
def _load_inventory_symbols(repo: Path) -> tuple[Any, Any, Any, Any, Any]:
inserted, previous = _project_imports(repo)
try:
from yuqei_contract_api.contract_templates import ( # type: ignore
_load_template_body,
list_contract_templates,
template_document_kind,
)
from yuqei_sdk.review_routing import ( # type: ignore
REVIEW_ROUTING_VERSION,
review_prompt_routes,
)
return (
_load_template_body,
list_contract_templates,
template_document_kind,
REVIEW_ROUTING_VERSION,
review_prompt_routes,
)
except ImportError as exc:
raise PublicationBatchError(f"cannot import frozen template inventory: {exc}") from exc
finally:
prefixes = ("yuqei_contract_api", "yuqei_sdk")
for name in list(sys.modules):
if (
name == prefixes[0]
or name.startswith(f"{prefixes[0]}.")
or name == prefixes[1]
or name.startswith(f"{prefixes[1]}.")
):
sys.modules.pop(name, None)
sys.modules.update(previous)
for value in inserted:
try:
sys.path.remove(value)
except ValueError: # pragma: no cover - defensive cleanup.
pass
def _load_executable_prompt_dependencies(repo: Path) -> list[dict[str, Any]]:
"""Render the candidate's actual runtime Prompt content for 14 identities."""
paths = (
repo / "yuqei-ai-platform/services/ai-platform-api/src",
repo / "yuqei-ai-sdk-python/src",
)
inserted: list[str] = []
for path in reversed(paths):
value = str(path)
if value not in sys.path:
sys.path.insert(0, value)
inserted.append(value)
prefixes = ("yuqei_ai_platform_api", "yuqei_sdk")
previous = {
name: module
for name, module in list(sys.modules.items())
if any(name == prefix or name.startswith(f"{prefix}.") for prefix in prefixes)
}
for name in previous:
sys.modules.pop(name, None)
try:
from yuqei_ai_platform_api.contract_drafting import ( # type: ignore
DRAFT_PROMPT_CONTENT,
DRAFT_PROMPT_NAMES,
DRAFT_PROMPT_VERSION,
)
from yuqei_ai_platform_api.drafting_prompt_modules import ( # type: ignore
drafting_module_evidence,
)
from yuqei_ai_platform_api.packaged_prompt_assets_import import ( # type: ignore
DEFAULT_VERSION,
load_packaged_prompt_assets,
)
from yuqei_ai_platform_api.review_scene_prompts import ( # type: ignore
review_module_evidence,
scene_review_template_for_route,
)
drafting_evidence = drafting_module_evidence(DRAFT_PROMPT_CONTENT)
results: list[dict[str, Any]] = [
{
"kind": "composed_drafting",
"runtime_key": DRAFT_PROMPT_NAMES[0],
"version": DRAFT_PROMPT_VERSION,
"content_sha256": _sha256_bytes(DRAFT_PROMPT_CONTENT.encode("utf-8")),
"publication_dependency": "six_module_composition",
"publication_module_dependencies": drafting_evidence,
}
]
review_routes = sorted(
item["key"]
for item in json.loads((repo / REVIEW_MODULE_PATH).read_text(encoding="utf-8"))[
"modules"
]
)
for route in review_routes:
template = scene_review_template_for_route(
route,
review_profile="scene_evaluation_v4",
scene_template_id="rc06-runtime-snapshot",
)
module_evidence = review_module_evidence(template)
if len(module_evidence) != 1 or module_evidence[0]["key"] != route:
raise PublicationBatchError(
f"runtime review Prompt does not contain its exact module: {route}"
)
results.append(
{
"kind": "new_review_module",
"runtime_key": route,
"version": template.version,
"content_sha256": template.content_hash,
"publication_dependency": "published_module",
"publication_module_dependencies": module_evidence,
}
)
packaged, _, duplicates = load_packaged_prompt_assets(repo / DEFAULT_PROMPT_PATH)
if duplicates:
raise PublicationBatchError("default Prompt runtime inventory contains duplicates")
by_key = {item.prompt_key: item for item in packaged}
for key in RUNTIME_EXISTING_DOMAIN_PROMPTS:
if key not in by_key:
raise PublicationBatchError(f"existing runtime domain Prompt is absent: {key}")
results.append(
{
"kind": "existing_domain_prompt",
"runtime_key": key,
"version": DEFAULT_VERSION,
"content_sha256": _sha256_bytes(by_key[key].content.encode("utf-8")),
"publication_dependency": "preexisting_domain_prompt",
"publication_module_dependencies": [],
}
)
results.sort(key=lambda item: (item["kind"], item["runtime_key"]))
if len(results) != EXPECTED_RUNTIME_PROMPT_COUNT or len(
{item["runtime_key"] for item in results}
) != EXPECTED_RUNTIME_PROMPT_COUNT:
raise PublicationBatchError("runtime Prompt dependency inventory must contain 14 identities")
return results
except (ImportError, OSError, ValueError, KeyError, TypeError) as exc:
raise PublicationBatchError(f"cannot render executable runtime Prompts: {exc}") from exc
finally:
for name in list(sys.modules):
if any(name == prefix or name.startswith(f"{prefix}.") for prefix in prefixes):
sys.modules.pop(name, None)
sys.modules.update(previous)
for value in inserted:
try:
sys.path.remove(value)
except ValueError: # pragma: no cover
pass
def _asset_hash_projection(asset: Mapping[str, Any]) -> dict[str, Any]:
return {
"id": asset["template_id"],
"contract_type": asset["contract_type"],
"required_variables": asset["required_variables"],
"optional_variables": asset["optional_variables"],
"validation_rules": asset["validation_rules"],
"input_schema": asset["input_schema"],
"clause_ids": asset["clause_ids"],
"review_rule_ids": asset["review_rule_ids"],
"body_content": asset["body_content"],
}
def _finish_asset(asset: dict[str, Any]) -> dict[str, Any]:
asset["body_sha256"] = _sha256_bytes(asset["body_content"].encode("utf-8"))
asset["input_schema_sha256"] = (
_sha256_json(asset["input_schema"]) if asset["input_schema"] is not None else None
)
asset["variables_sha256"] = _sha256_json(
{"required": asset["required_variables"], "optional": asset["optional_variables"]}
)
asset["review_identity_sha256"] = _sha256_json(asset["review_identity"])
calculated_content = _sha256_json(_asset_hash_projection(asset))
if asset.get("content_sha256") != calculated_content:
raise PublicationBatchError(f"runtime content hash drift for {asset.get('template_id')}")
payload = {key: value for key, value in asset.items() if key != "asset_payload_sha256"}
asset["asset_payload_sha256"] = _sha256_json(payload)
return asset
def load_runtime_inventory(
repo: Path,
*,
frozen_source_paths: list[str] | None = None,
) -> dict[str, Any]:
"""Load the real source catalog without consulting a service or database."""
(
_load_template_body,
list_contract_templates,
template_document_kind,
REVIEW_ROUTING_VERSION,
review_prompt_routes,
) = _load_inventory_symbols(repo)
page = list_contract_templates()
if page.total != EXPECTED_ASSET_COUNT or len(page.items) != EXPECTED_ASSET_COUNT:
raise PublicationBatchError(
f"source catalog must contain exactly {EXPECTED_ASSET_COUNT} templates; got {page.total}"
)
assets: list[dict[str, Any]] = []
seen_assets: set[str] = set()
for template in page.items:
if template.id in seen_assets:
raise PublicationBatchError(f"duplicate template ID: {template.id}")
seen_assets.add(template.id)
body = _load_template_body(template.id)
schema = template.input_schema.model_dump(mode="json") if template.input_schema else None
scene = schema.get("scene") if isinstance(schema, dict) else None
document_kind = (
scene.get("document_kind")
if isinstance(scene, dict) and isinstance(scene.get("document_kind"), str)
else template_document_kind(template.contract_type)
)
required = [item.model_dump(mode="json") for item in template.required_variables]
optional = [item.model_dump(mode="json") for item in template.optional_variables]
routes = list(review_prompt_routes(template.contract_type, template.id))
review_identity = {
"routing_version": REVIEW_ROUTING_VERSION,
"prompt_routes": routes,
"review_rule_ids": list(template.review_rule_ids),
}
assets.append(
_finish_asset(
{
"template_id": template.id,
"name": template.name,
"version": template.lifecycle_version or template.version,
"document_kind": document_kind,
"contract_type": template.contract_type,
"source": template.source,
"source_lifecycle_status": template.lifecycle_status,
"body_content": body,
"content_sha256": template.content_sha256,
"input_schema": schema,
"required_variables": required,
"optional_variables": optional,
"validation_rules": list(template.validation_rules),
"clause_ids": list(template.clause_ids),
"review_rule_ids": list(template.review_rule_ids),
"review_identity": review_identity,
}
)
)
assets.sort(key=lambda item: item["template_id"])
drafting_raw, _ = secure_read_json(repo / DRAFTING_MODULE_PATH, "drafting module source")
review_raw, _ = secure_read_json(repo / REVIEW_MODULE_PATH, "review module source")
if not isinstance(drafting_raw, list) or len(drafting_raw) != EXPECTED_DRAFTING_MODULE_COUNT:
raise PublicationBatchError("drafting module source must contain exactly 6 modules")
if not isinstance(review_raw, dict) or review_raw.get("schema_version") != "review-scene-modules.v1":
raise PublicationBatchError("review module source schema is invalid")
review_modules = review_raw.get("modules")
if not isinstance(review_modules, list) or len(review_modules) != EXPECTED_REVIEW_MODULE_COUNT:
raise PublicationBatchError("review module source must contain exactly 8 modules")
modules: list[dict[str, Any]] = []
for source in drafting_raw:
row = _require_keys(source, "drafting module", ("key", "version", "instructions"))
key = _require_string(row["key"], "drafting module key", max_length=128)
content = _require_string(row["instructions"], f"{key} content", max_length=200_000)
module = {
"category": "drafting",
"key": key,
"version": _require_string(row["version"], f"{key} version", max_length=128),
"content": content,
"content_sha256": _sha256_bytes(content.encode("utf-8")),
"publication_mapping": {
"prompt_key": "contract_drafting",
"route": "contract_drafting",
},
}
module["module_payload_sha256"] = _sha256_json(module)
modules.append(module)
for source in review_modules:
row = _require_keys(source, "review module", ("key", "version", "text"))
key = _require_string(row["key"], "review module key", max_length=128)
content = _require_string(row["text"], f"{key} content", max_length=200_000)
module = {
"category": "review",
"key": key,
"version": _require_string(row["version"], f"{key} version", max_length=128),
"content": content,
"content_sha256": _sha256_bytes(content.encode("utf-8")),
"publication_mapping": {"prompt_key": key, "route": key},
}
module["module_payload_sha256"] = _sha256_json(module)
modules.append(module)
modules.sort(key=lambda item: (item["category"], item["key"]))
module_keys = [item["key"] for item in modules]
if len(module_keys) != EXPECTED_MODULE_COUNT or len(set(module_keys)) != EXPECTED_MODULE_COUNT:
raise PublicationBatchError("the 14 Prompt modules must have unique keys")
default_raw, default_raw_sha = secure_read_json(repo / DEFAULT_PROMPT_PATH, "default Prompt source")
if not isinstance(default_raw, dict) or not isinstance(default_raw.get("assets"), list):
raise PublicationBatchError("default Prompt source is invalid")
default_assets = default_raw["assets"]
if len(default_assets) != EXPECTED_DEFAULT_PROMPT_COUNT:
raise PublicationBatchError("default Prompt inventory must contain exactly 46 assets")
default_inventory = []
for asset in default_assets:
if not isinstance(asset, dict):
raise PublicationBatchError("default Prompt asset is invalid")
key = _require_string(asset.get("prompt_key"), "default Prompt key", max_length=128)
default_inventory.append(
{
"prompt_key": key,
"prompt_type": _require_string(asset.get("prompt_type"), f"{key} type", max_length=128),
"asset_sha256": _sha256_json(asset),
}
)
if len({item["prompt_key"] for item in default_inventory}) != EXPECTED_DEFAULT_PROMPT_COUNT:
raise PublicationBatchError("default Prompt inventory contains duplicate keys")
if set(module_keys).intersection(item["prompt_key"] for item in default_inventory):
raise PublicationBatchError("14-module batch must remain distinct from 46 default Prompt assets")
default_inventory.sort(key=lambda item: item["prompt_key"])
golden_raw = secure_read_bytes(repo / GOLDEN_INVENTORY_PATH, "Golden inventory")
try:
rows = list(csv.DictReader(golden_raw.decode("utf-8-sig").splitlines()))
except UnicodeDecodeError as exc:
raise PublicationBatchError("Golden inventory is not valid UTF-8") from exc
if len(rows) != EXPECTED_GOLDEN_COUNT:
raise PublicationBatchError("Golden inventory must contain exactly 31 rows")
golden_cases: list[dict[str, Any]] = []
for row in rows:
sample_id = _require_string(row.get("sample_id"), "Golden sample ID", max_length=128)
asset_id = _require_string(row.get("template_id"), f"{sample_id} asset ID", max_length=128)
suite = "clause_recommendation" if asset_id.startswith("CLAUSE-") else "contract_generation"
golden_cases.append(
{
"sample_id": sample_id,
"suite": suite,
"asset_id": asset_id,
"source_case_sha256": _sha256_json(row),
}
)
golden_cases.sort(key=lambda item: item["sample_id"])
if len({item["sample_id"] for item in golden_cases}) != EXPECTED_GOLDEN_COUNT:
raise PublicationBatchError("Golden inventory contains duplicate sample IDs")
if sum(item["suite"] == "contract_generation" for item in golden_cases) != EXPECTED_GOLDEN_GENERATION_COUNT:
raise PublicationBatchError("Golden generation inventory must contain exactly 23 cases")
if sum(item["suite"] == "clause_recommendation" for item in golden_cases) != EXPECTED_GOLDEN_CLAUSE_COUNT:
raise PublicationBatchError("Golden clause inventory must contain exactly 8 cases")
return {
"assets": assets,
"prompt_modules": modules,
"runtime_prompt_dependencies": _load_executable_prompt_dependencies(repo),
"default_prompt_boundary": {
"included_in_publication_batch": False,
"count": len(default_inventory),
"source_path": DEFAULT_PROMPT_PATH,
"source_raw_sha256": default_raw_sha,
"inventory": default_inventory,
"inventory_sha256": _sha256_json(default_inventory),
"boundary_note": (
"These 46 default Prompt assets are an existing, separate inventory; "
"they are not the 14 RC-06 authored modules."
),
},
"golden_cases": golden_cases,
"source_paths": (
list(frozen_source_paths)
if frozen_source_paths is not None
else _inventory_source_paths(repo)
),
}
def validate_image_identities(payload: Any, commit: str, tag: str) -> dict[str, Any]:
if not isinstance(payload, dict):
raise PublicationBatchError("image identities must be an object")
if payload.get("schema_version") == IMAGE_SCHEMA_VERSION:
document = _require_keys(payload, "image identities", ("schema_version", "commit", "tag", "images"))
document_commit = document["commit"]
document_tag = document["tag"]
images = document["images"]
source_schema = IMAGE_SCHEMA_VERSION
elif payload.get("schema_version") == "yuqei.installable-release-manifest.v1":
candidate = payload.get("candidate")
if not isinstance(candidate, dict):
raise PublicationBatchError("installable release candidate identity is missing")
document_commit = candidate.get("commit")
document_tag = candidate.get("tag")
images = payload.get("images")
source_schema = "yuqei.installable-release-manifest.v1"
else:
raise PublicationBatchError("unsupported image identities schema")
if document_commit != commit or document_tag != tag:
raise PublicationBatchError("image identities candidate does not match commit/tag")
if not isinstance(images, list) or len(images) != len(REQUIRED_IMAGE_ROLES):
raise PublicationBatchError("image identities must contain the four application images")
normalized = []
roles: set[str] = set()
manifest_digests: set[str] = set()
for number, item in enumerate(images):
if not isinstance(item, dict):
raise PublicationBatchError(f"image {number} is invalid")
if source_schema == IMAGE_SCHEMA_VERSION:
row = _require_keys(
item,
f"image {number}",
("role", "repository", "manifest_digest", "config_digest"),
)
repository_value = row["repository"]
else:
row = item
repository_value = row.get("image_name") or row.get("registry_reference")
role = _require_string(row["role"], f"image {number} role", max_length=64)
repository = _require_string(repository_value, f"image {role} repository", max_length=256)
manifest_digest = row["manifest_digest"]
config_digest = row["config_digest"]
if not isinstance(manifest_digest, str) or not manifest_digest.startswith("sha256:"):
raise PublicationBatchError(f"image {role} manifest digest is invalid")
if not isinstance(config_digest, str) or not config_digest.startswith("sha256:"):
raise PublicationBatchError(f"image {role} config digest is invalid")
_require_sha(manifest_digest.removeprefix("sha256:"), f"image {role} manifest digest")
_require_sha(config_digest.removeprefix("sha256:"), f"image {role} config digest")
if role in roles or manifest_digest in manifest_digests:
raise PublicationBatchError("duplicate image role or manifest digest")
roles.add(role)
manifest_digests.add(manifest_digest)
normalized.append(
{
"role": role,
"repository": repository,
"manifest_digest": manifest_digest,
"config_digest": config_digest,
}
)
if roles != set(REQUIRED_IMAGE_ROLES):
raise PublicationBatchError(f"image roles mismatch: {sorted(roles)}")
normalized.sort(key=lambda item: REQUIRED_IMAGE_ROLES.index(item["role"]))
return {
"images": normalized,
"identity_set_sha256": _sha256_json(normalized),
"source_schema": source_schema,
}
def _validate_rc05_candidate_binding(value: Any) -> dict[str, Any]:
candidate = _require_keys(
value,
"RC-05 candidate binding",
("schema_version", "commit", "tag", "source_manifest", "image_identities"),
)
if (
candidate["schema_version"] != RC05_CANDIDATE_SCHEMA_VERSION
or not COMMIT_RE.fullmatch(str(candidate["commit"]))
or not TAG_RE.fullmatch(str(candidate["tag"]))
or ".." in candidate["tag"]
or "//" in candidate["tag"]
):
raise PublicationBatchError("RC-05 candidate binding identity is invalid")
source = _require_keys(
candidate["source_manifest"],
"RC-05 candidate source manifest binding",
("schema_version", "raw_sha256", "payload_sha256"),
)
if source["schema_version"] != "yuqei.release-source-manifest.v1":
raise PublicationBatchError("RC-05 candidate source manifest schema is invalid")
_require_sha(source["raw_sha256"], "RC-05 candidate source manifest raw SHA-256")
_require_sha(
source["payload_sha256"], "RC-05 candidate source manifest payload SHA-256"
)
image_binding = _require_keys(
candidate["image_identities"],
"RC-05 candidate image binding",
("schema_version", "raw_sha256", "identity_set_sha256", "images"),
)
if image_binding["schema_version"] not in {
IMAGE_SCHEMA_VERSION,
"yuqei.installable-release-manifest.v1",
}:
raise PublicationBatchError("RC-05 candidate image binding schema is invalid")
_require_sha(image_binding["raw_sha256"], "RC-05 candidate image raw SHA-256")
identity_set_sha = _require_sha(
image_binding["identity_set_sha256"], "RC-05 candidate image set SHA-256"
)
images = image_binding["images"]
if not isinstance(images, list) or len(images) != len(REQUIRED_IMAGE_ROLES):
raise PublicationBatchError("RC-05 candidate must bind all four release images")
normalized: list[dict[str, Any]] = []
roles: set[str] = set()
manifest_digests: set[str] = set()
for index, value_row in enumerate(images):
row = _require_keys(
value_row,
f"RC-05 candidate image {index}",
("role", "repository", "manifest_digest", "config_digest"),
)
role = row["role"]
repository = _require_string(
row["repository"], f"RC-05 candidate image {index} repository", max_length=256
)
if role not in REQUIRED_IMAGE_ROLES or role in roles:
raise PublicationBatchError("RC-05 candidate image role inventory is invalid")
manifest_digest = row["manifest_digest"]
config_digest = row["config_digest"]
if (
not isinstance(manifest_digest, str)
or not manifest_digest.startswith("sha256:")
or not isinstance(config_digest, str)
or not config_digest.startswith("sha256:")
):
raise PublicationBatchError("RC-05 candidate image digest is invalid")
_require_sha(
manifest_digest.removeprefix("sha256:"),
f"RC-05 candidate image {role} manifest digest",
)
_require_sha(
config_digest.removeprefix("sha256:"),
f"RC-05 candidate image {role} config digest",
)
if manifest_digest in manifest_digests:
raise PublicationBatchError("RC-05 candidate image manifest digests must be unique")
roles.add(role)
manifest_digests.add(manifest_digest)
normalized.append(
{
"role": role,
"repository": repository,
"manifest_digest": manifest_digest,
"config_digest": config_digest,
}
)
normalized.sort(key=lambda item: REQUIRED_IMAGE_ROLES.index(item["role"]))
if images != normalized or roles != set(REQUIRED_IMAGE_ROLES):
raise PublicationBatchError("RC-05 candidate images are not canonically ordered")
if _sha256_json(normalized) != identity_set_sha:
raise PublicationBatchError("RC-05 candidate image identity-set digest drift")
return dict(candidate)
def _validate_rc05_release_controls(
value: Any, *, cases: list[dict[str, Any]]
) -> dict[str, Any]:
controls = _require_keys(
value,
"RC-05 release controls",
(
"schema_version", "canary_case_ids", "failure_classes",
"expected_operations",
),
)
canaries = controls["canary_case_ids"]
failure_classes = controls["failure_classes"]
expected_operations = controls["expected_operations"]
case_ids = [case["case_id"] for case in cases]
expected_operation_map = {
case["case_id"]: list(case["operations"])
for case in cases
}
if (
controls["schema_version"] != RC05_RELEASE_CONTROLS_SCHEMA_VERSION
or canaries != list(EXPECTED_RC05_CANARY_CASE_IDS)
or not isinstance(failure_classes, dict)
or set(failure_classes) != set(case_ids)
or not isinstance(expected_operations, dict)
or expected_operations != expected_operation_map
):
raise PublicationBatchError("RC-05 release controls identity or coverage drift")
for case in cases:
failure_class = _require_string(
case.get("failure_class"),
f"RC-05 {case['case_id']} failure class",
max_length=128,
)
if (
not STABLE_ID_RE.fullmatch(failure_class)
or failure_classes[case["case_id"]] != failure_class
):
raise PublicationBatchError("RC-05 failure-class circuit binding drift")
return dict(controls)
def validate_rc05_plan(
payload: Any, *, expected_candidate: Mapping[str, Any] | None = None
) -> dict[str, Any]:
plan = _require_keys(
payload,
"RC-05 plan",
(
"schema_version",
"prepared_at",
"model",
"reasoning_effort",
"timeout_seconds",
"case_count",
"drafting_case_count",
"supplemental_case_count",
"operation_limits",
"total_provider_call_budget",
"candidate",
"release_controls",
"source_pins",
"cases",
"limitations",
),
)
if plan["schema_version"] != RC05_PLAN_SCHEMA_VERSION:
raise PublicationBatchError(
"legacy or unsupported RC-05 plan schema is read-only diagnostic material"
)
_parse_time(plan["prepared_at"], "RC-05 plan prepared_at")
candidate_binding = _validate_rc05_candidate_binding(plan["candidate"])
if expected_candidate is not None and candidate_binding != dict(expected_candidate):
raise PublicationBatchError("RC-05 plan candidate binding differs from the frozen candidate")
payload = plan
if payload.get("model") != "gpt-5.6-sol" or payload.get("reasoning_effort") != "medium":
raise PublicationBatchError("RC-05 plan model identity is not the frozen release configuration")
if payload.get("timeout_seconds") != 300 or payload.get("case_count") != 144:
raise PublicationBatchError("RC-05 plan timeout or case count drift")
if (
payload.get("drafting_case_count") != 120
or payload.get("supplemental_case_count") != 24
or payload.get("total_provider_call_budget") != 280
or payload.get("operation_limits") != EXPECTED_RC05_OPERATION_LIMITS
):
raise PublicationBatchError("RC-05 plan inventory, operation limits, or budget drift")
cases = payload.get("cases")
if not isinstance(cases, list) or len(cases) != 144:
raise PublicationBatchError("RC-05 plan case inventory is incomplete")
case_ids: list[str] = []
operation_counts = {operation: 0 for operation in EXPECTED_RC05_OPERATION_LIMITS}
total_case_budget = 0
drafting_count = 0
supplemental_count = 0
for number, case in enumerate(cases):
if not isinstance(case, dict):
raise PublicationBatchError(f"RC-05 plan case {number} must be an object")
case_id = case.get("case_id")
if not isinstance(case_id, str) or not STABLE_ID_RE.fullmatch(case_id):
raise PublicationBatchError("RC-05 plan contains an invalid case identity")
case_ids.append(case_id)
operations = case.get("operations")
budget = case.get("provider_call_budget")
if (
not isinstance(operations, list)
or not operations
or len(operations) != len(set(operations))
or any(operation not in EXPECTED_RC05_OPERATION_LIMITS for operation in operations)
):
raise PublicationBatchError(f"RC-05 case operations are invalid: {case_id}")
if not isinstance(budget, int) or isinstance(budget, bool) or budget != len(operations):
raise PublicationBatchError(f"RC-05 case provider budget is invalid: {case_id}")
for operation in operations:
operation_counts[operation] += 1
total_case_budget += budget
kind = case.get("kind")
if kind == "drafting":
drafting_count += 1
required = {
"source_case_id", "mode", "template_id", "document_kind", "title",
"instructions", "values", "values_sha256", "candidate_policy",
"expectation_profile", "template_content_sha256",
"template_input_schema_sha256", "draft_request_projection", "auto_repair",
}
if not required.issubset(case):
raise PublicationBatchError(f"RC-05 drafting case is incomplete: {case_id}")
if (
not isinstance(case["source_case_id"], str)
or not STABLE_ID_RE.fullmatch(case["source_case_id"])
or not isinstance(case["values"], dict)
):
raise PublicationBatchError(f"RC-05 drafting case identity or values drift: {case_id}")
if _sha256_json(case["values"]) != _require_sha(
case["values_sha256"], f"RC-05 {case_id} values SHA-256"
):
raise PublicationBatchError(f"RC-05 drafting values hash drift: {case_id}")
for field in ("template_content_sha256", "template_input_schema_sha256"):
if case[field] is not None:
_require_sha(case[field], f"RC-05 {case_id} {field}")
policy = case["candidate_policy"]
if not isinstance(policy, dict):
raise PublicationBatchError(f"RC-05 drafting policy is invalid: {case_id}")
expected_semantic = "semantic_review" in operations
expected_repair = {"repair_draft", "repair_review"}.issubset(operations)
if (
policy.get("semantic_review") is not expected_semantic
or policy.get("auto_repair") is not expected_repair
or case["auto_repair"] is not expected_repair
):
raise PublicationBatchError(f"RC-05 drafting operation policy drift: {case_id}")
elif kind in {"specialist_review", "intake"}:
supplemental_count += 1
if (
operations != [kind]
or case.get("operation") != kind
or case.get("mode") != kind
or case.get("source_case_id") != case_id
or not isinstance(case.get("request"), dict)
or _sha256_json(case["request"]) != _require_sha(
case.get("request_sha256"), f"RC-05 {case_id} request SHA-256"
)
):
raise PublicationBatchError(f"RC-05 supplemental case drift: {case_id}")
else:
raise PublicationBatchError(f"RC-05 case kind is invalid: {case_id}")
if len(set(case_ids)) != 144:
raise PublicationBatchError("RC-05 plan contains duplicate case identities")
if (
drafting_count != 120
or supplemental_count != 24
or operation_counts != EXPECTED_RC05_OPERATION_LIMITS
or total_case_budget != 280
):
raise PublicationBatchError("RC-05 case operations or provider budgets do not reconcile")
release_controls = _validate_rc05_release_controls(
payload["release_controls"], cases=cases
)
source_pins = payload.get("source_pins")
if not isinstance(source_pins, dict) or not source_pins:
raise PublicationBatchError("RC-05 plan source pins are missing")
for relative, digest in source_pins.items():
if (
not isinstance(relative, str)
or not relative
or relative.startswith(("/", "\\"))
or ".." in PurePath(relative).parts
or "\\" in relative
):
raise PublicationBatchError("RC-05 plan contains an unsafe source pin path")
_require_sha(digest, f"RC-05 source pin {relative}")
return {
"schema_version": payload["schema_version"],
"model": payload["model"],
"reasoning_effort": payload["reasoning_effort"],
"timeout_seconds": payload["timeout_seconds"],
"case_count": payload["case_count"],
"drafting_case_count": payload["drafting_case_count"],
"supplemental_case_count": payload["supplemental_case_count"],
"operation_limits": payload["operation_limits"],
"total_provider_call_budget": payload["total_provider_call_budget"],
"case_inventory_sha256": _sha256_json(cases),
"source_pins_sha256": _sha256_json(source_pins),
"candidate": candidate_binding,
"release_controls": release_controls,
}
def verify_rc05_source_pins(
repo: Path,
commit: str,
source_manifest: Any,
plan: Mapping[str, Any],
) -> None:
index, _ = _source_manifest_index(source_manifest, commit)
pins = plan["source_pins"]
for relative, digest in pins.items():
if index.get(relative) != digest:
raise PublicationBatchError(
f"RC-05 source pin differs from candidate source manifest: {relative}"
)
committed = bytes(_run_git(repo, "show", f"{commit}:{relative}", binary=True))
if _sha256_bytes(committed) != digest:
raise PublicationBatchError(
f"RC-05 source pin differs from candidate commit: {relative}"
)
def validate_rc05_plan_identity(value: Any) -> dict[str, Any]:
identity = _require_keys(
value,
"RC-05 plan identity",
(
"schema_version",
"model",
"reasoning_effort",
"timeout_seconds",
"case_count",
"drafting_case_count",
"supplemental_case_count",
"operation_limits",
"total_provider_call_budget",
"case_inventory_sha256",
"source_pins_sha256",
"candidate",
"release_controls",
),
)
if (
identity["schema_version"] != RC05_PLAN_SCHEMA_VERSION
or identity["model"] != "gpt-5.6-sol"
or identity["reasoning_effort"] != "medium"
or identity["timeout_seconds"] != 300
or identity["case_count"] != 144
or identity["drafting_case_count"] != 120
or identity["supplemental_case_count"] != 24
or identity["operation_limits"] != EXPECTED_RC05_OPERATION_LIMITS
or identity["total_provider_call_budget"] != 280
):
raise PublicationBatchError("RC-05 plan identity drift")
_require_sha(identity["case_inventory_sha256"], "RC-05 case inventory SHA-256")
_require_sha(identity["source_pins_sha256"], "RC-05 source pins SHA-256")
_validate_rc05_candidate_binding(identity["candidate"])
controls = _require_keys(
identity["release_controls"],
"RC-05 plan identity release controls",
(
"schema_version", "canary_case_ids", "failure_classes",
"expected_operations",
),
)
failure_classes = controls["failure_classes"]
expected_operations = controls["expected_operations"]
operation_counts = {
operation: 0 for operation in EXPECTED_RC05_OPERATION_LIMITS
}
expected_operations_valid = (
isinstance(expected_operations, dict)
and isinstance(failure_classes, dict)
and set(expected_operations) == set(failure_classes)
)
if expected_operations_valid:
for case_id, operations in expected_operations.items():
if (
not isinstance(case_id, str)
or not STABLE_ID_RE.fullmatch(case_id)
or not isinstance(operations, list)
or not operations
or len(operations) != len(set(operations))
or any(
operation not in EXPECTED_RC05_OPERATION_LIMITS
for operation in operations
)
):
expected_operations_valid = False
break
for operation in operations:
operation_counts[operation] += 1
if (
controls["schema_version"] != RC05_RELEASE_CONTROLS_SCHEMA_VERSION
or controls["canary_case_ids"] != list(EXPECTED_RC05_CANARY_CASE_IDS)
or not isinstance(failure_classes, dict)
or len(failure_classes) != 144
or any(
not isinstance(key, str)
or not STABLE_ID_RE.fullmatch(key)
or not isinstance(value, str)
or not STABLE_ID_RE.fullmatch(value)
for key, value in failure_classes.items()
)
or not expected_operations_valid
or operation_counts != EXPECTED_RC05_OPERATION_LIMITS
):
raise PublicationBatchError("RC-05 plan identity release controls drift")
return dict(identity)
def _validate_rc05_case_operation_coverage(
value: Any,
*,
plan_cases: Mapping[str, Mapping[str, Any]],
result_cases: Mapping[str, Mapping[str, Any]],
) -> list[dict[str, Any]]:
if not isinstance(value, list) or len(value) != len(plan_cases):
raise PublicationBatchError(
"RC-05 case-operation coverage must contain all 144 cases"
)
repair_pair = {"repair_draft", "repair_review"}
coverage: dict[str, dict[str, Any]] = {}
for number, raw in enumerate(value):
row = _require_keys(
raw,
f"RC-05 case-operation coverage {number}",
(
"case_id", "declared_operations", "mandatory_operations",
"actual_operations", "provider_call_count", "passed",
),
)
case_id = row["case_id"]
if not isinstance(case_id, str) or case_id not in plan_cases or case_id in coverage:
raise PublicationBatchError("RC-05 case-operation coverage identity drift")
declared = row["declared_operations"]
mandatory = row["mandatory_operations"]
actual = row["actual_operations"]
if not all(isinstance(items, list) for items in (declared, mandatory, actual)):
raise PublicationBatchError(
f"RC-05 case-operation coverage lists are invalid: {case_id}"
)
if any(
not isinstance(operation, str)
for items in (declared, mandatory, actual)
for operation in items
):
raise PublicationBatchError(
f"RC-05 case-operation coverage operation is invalid: {case_id}"
)
plan_operations = plan_cases[case_id]["operations"]
declared_set = set(declared)
actual_set = set(actual)
expected_mandatory = set(plan_operations) - repair_pair
missing = expected_mandatory - actual_set
extra = actual_set - set(plan_operations)
repair_actual = actual_set & repair_pair
expected_calls = result_cases[case_id]["provider_call_count"]
if (
declared != plan_operations
or len(declared) != len(declared_set)
or mandatory != sorted(expected_mandatory)
or actual != sorted(actual)
or len(actual) != len(actual_set)
or missing
or extra
or repair_actual not in (set(), repair_pair)
or row["provider_call_count"] != expected_calls
or len(actual) != expected_calls
or row["passed"] is not True
):
raise PublicationBatchError(
f"RC-05 case-operation coverage is not release-green: {case_id}"
)
coverage[case_id] = dict(row)
if set(coverage) != set(plan_cases):
raise PublicationBatchError("RC-05 case-operation coverage inventory is incomplete")
return [coverage[case_id] for case_id in sorted(coverage)]
def validate_rc05_terminal_evidence(
plan: Mapping[str, Any],
plan_raw_sha256: str,
summary: Any,
summary_raw_sha256: str,
ledger_identity: Any,
ledger_identity_raw_sha256: str,
campaign_identity: Any,
campaign_identity_raw_sha256: str,
) -> dict[str, Any]:
"""Validate a complete real-provider RC-05 terminal evidence chain.
This is an integrity and cross-document consistency gate. It deliberately
does not turn RC-06 into a publication command or claim authentication.
"""
plan_sha = _require_sha(plan_raw_sha256, "RC-05 plan raw SHA-256")
for digest, label in (
(summary_raw_sha256, "RC-05 summary raw SHA-256"),
(ledger_identity_raw_sha256, "RC-05 ledger identity raw SHA-256"),
(campaign_identity_raw_sha256, "RC-05 campaign identity raw SHA-256"),
):
_require_sha(digest, label)
ledger = _require_keys(
ledger_identity,
"RC-05 ledger identity",
(
"schema_version", "plan_sha256", "operation_limits", "case_limits",
"source_pins", "real_provider", "candidate_binding", "release_controls", "authority",
"integrity_not_authentication", "historical_usage",
),
)
if (
ledger["schema_version"] != RC05_LEDGER_SCHEMA_VERSION
or ledger["plan_sha256"] != plan_sha
or ledger["operation_limits"] != plan["operation_limits"]
or ledger["source_pins"] != dict(sorted(plan["source_pins"].items()))
or ledger["candidate_binding"] != plan["candidate"]
or ledger["release_controls"] != plan["release_controls"]
or ledger["real_provider"] is not True
or ledger["integrity_not_authentication"] is not True
):
raise PublicationBatchError("RC-05 ledger identity does not match the frozen real plan")
expected_case_limits = {
case["case_id"]: case["provider_call_budget"] for case in sorted(
plan["cases"], key=lambda item: item["case_id"]
)
}
if ledger["case_limits"] != expected_case_limits:
raise PublicationBatchError("RC-05 ledger case budgets do not match the plan")
authority = _require_keys(
ledger["authority"],
"RC-05 ledger authority",
("mode", "registry_root", "run_key", "bound_output_dir"),
)
if authority["mode"] != "global_registry":
raise PublicationBatchError("RC-05 real ledger must use the global campaign registry")
for key in ("registry_root", "bound_output_dir"):
_require_string(authority[key], f"RC-05 ledger authority {key}", max_length=4096)
_require_sha(authority["run_key"], "RC-05 ledger run key")
ledger_identity_sha256 = _sha256_json(ledger)
historical = ledger["historical_usage"]
if not isinstance(historical, dict):
raise PublicationBatchError("RC-05 ledger historical usage is missing")
historical_count = historical.get("provider_call_count")
repair_count = historical.get("repair_budget_charged")
if (
not isinstance(historical_count, int)
or isinstance(historical_count, bool)
or historical_count < 0
or historical_count > 280
or not isinstance(repair_count, int)
or isinstance(repair_count, bool)
or repair_count < 0
or repair_count > 16
or repair_count > historical_count
):
raise PublicationBatchError("RC-05 historical call counts are invalid")
historical_receipt_sha = _require_sha(
historical.get("receipt_sha256"), "RC-05 historical receipt SHA-256"
)
historical_attempts_sha = _require_sha(
historical.get("attempts_sha256"), "RC-05 historical attempts SHA-256"
)
historical_attempts = historical.get("attempts")
if (
historical_count != 4
or not isinstance(historical_attempts, list)
or len(historical_attempts) != historical_count
or _sha256_json(historical_attempts) != historical_attempts_sha
):
raise PublicationBatchError("RC-05 historical attempt inventory or digest drift")
attempt_index: dict[str, dict[str, Any]] = {}
for attempt in historical_attempts:
if (
not isinstance(attempt, dict)
or set(attempt) != RC05_HISTORICAL_ATTEMPT_KEYS
or not STABLE_ID_RE.fullmatch(str(attempt.get("attempt_id", "")))
):
raise PublicationBatchError("RC-05 historical attempt identity is invalid")
attempt_id = attempt["attempt_id"]
if attempt_id in attempt_index:
raise PublicationBatchError("RC-05 historical attempt identities must be unique")
disposition = attempt.get("disposition")
if (
not isinstance(disposition, dict)
or set(disposition) != {
"resolution_status", "release_eligible", "reason",
"replacement_case_id", "replacement_operation",
}
or not isinstance(disposition.get("release_eligible"), bool)
):
raise PublicationBatchError("RC-05 historical attempt disposition is invalid")
for field in (
"plan_sha256", "request_sha256", "response_sha256", "identity_file_sha256",
"ledger_identity_sha256", "claim_sha256", "finish_sha256", "before_sha256",
"after_sha256",
):
_require_sha(attempt[field], f"RC-05 historical {field}")
if (
attempt["operation"] not in EXPECTED_RC05_OPERATION_LIMITS
or attempt["provider_status"] not in {"succeeded", "failed", "cancelled"}
or attempt["business_status"] not in {
"succeeded", "failed", "cancelled", "awaiting_human", "resolved",
}
or attempt["provider"] != "codex-cli-development"
or attempt["model"] != "gpt-5.6-sol"
or not isinstance(attempt["timed_out"], bool)
):
raise PublicationBatchError("RC-05 historical provider outcome drift")
_require_nonnegative_number(
attempt["elapsed_seconds"], "RC-05 historical elapsed_seconds"
)
if disposition["release_eligible"]:
if (
disposition.get("resolution_status") != "resolved"
or disposition.get("replacement_case_id") is not None
or disposition.get("replacement_operation") is not None
or not _historical_attempt_can_be_release_eligible(attempt)
):
raise PublicationBatchError("RC-05 resolved historical disposition drift")
elif (
disposition.get("resolution_status") != "requires_replacement"
or disposition.get("replacement_case_id") not in {
case["case_id"] for case in plan["cases"]
}
or disposition.get("replacement_operation") not in EXPECTED_RC05_OPERATION_LIMITS
):
raise PublicationBatchError("RC-05 replacement disposition is not bound to the plan")
attempt_index[attempt_id] = attempt
campaign = _require_keys(
campaign_identity,
"RC-05 campaign identity",
(
"schema_version", "campaign_id", "historical_receipt_sha256",
"historical_attempts_sha256", "historical_provider_call_count",
"historical_repair_budget_charged", "provider_call_limit",
"repair_call_limit",
),
)
if (
campaign["schema_version"] != RC05_CAMPAIGN_SCHEMA_VERSION
or campaign["campaign_id"] != "rc05-real-usage-v2"
or campaign["historical_receipt_sha256"] != historical_receipt_sha
or campaign["historical_attempts_sha256"] != historical_attempts_sha
or campaign["historical_provider_call_count"] != historical_count
or campaign["historical_repair_budget_charged"] != repair_count
or campaign["provider_call_limit"] != 280
or campaign["repair_call_limit"] != 16
):
raise PublicationBatchError("RC-05 campaign identity does not match ledger history")
campaign_identity_sha256 = _sha256_json(campaign)
run = _require_keys(
summary,
"RC-05 terminal summary",
(
"schema_version", "plan_raw_sha256", "real_provider", "execution_mode",
"case_count", "drafting_case_count", "asset_count", "supplemental_case_count",
"cases", "complete", "passed", "matrix_execution_passed",
"release_quality_gate_passed", "automated_model_quality_release_passed",
"human_legal_approval_in_scope", "current_run_passed",
"current_selection_passed", "historical_release_eligible",
"historical_remediation", "overall_release_passed", "selected_release_quality_passed",
"selected_passed", "provider_call_count", "provider_call_count_scope",
"current_plan_provider_call_count", "campaign_new_provider_call_count",
"ledger", "provider_call_count_including_historical", "historical_usage",
"operation_statistics", "historical_by_operation", "combined_call_counts",
"case_operation_coverage", "case_operation_coverage_passed",
"selected_operation_coverage_passed",
"operation_statistics_complete", "operation_evidence_errors",
"case_elapsed_seconds", "live_database_writes", "live_service_calls",
"member_release_acceptance_completed", "not_legal_approval",
),
)
required_green = (
"complete", "passed", "matrix_execution_passed", "release_quality_gate_passed",
"automated_model_quality_release_passed",
"current_run_passed", "current_selection_passed", "historical_release_eligible",
"overall_release_passed", "selected_release_quality_passed", "selected_passed",
"case_operation_coverage_passed", "selected_operation_coverage_passed",
"operation_statistics_complete",
)
if (
run["schema_version"] != RC05_SUMMARY_SCHEMA_VERSION
or run["plan_raw_sha256"] != plan_sha
or run["real_provider"] is not True
or run["execution_mode"] != "real"
or any(run[field] is not True for field in required_green)
or run["case_count"] != 144
or run["drafting_case_count"] != 120
or run["asset_count"] != 60
or run["supplemental_case_count"] != 24
or run["live_database_writes"] != 0
or run["live_service_calls"] != 0
or run["operation_evidence_errors"] != []
or run["human_legal_approval_in_scope"] is not False
or run["member_release_acceptance_completed"] is not False
or run["not_legal_approval"] is not True
):
raise PublicationBatchError("RC-05 terminal summary is not a complete real green run")
expected_summary_history = {
"provider_call_count": historical_count,
"repair_budget_charged": repair_count,
"attempts": historical_attempts,
"receipt_sha256": historical_receipt_sha,
}
if run["historical_usage"] != expected_summary_history:
raise PublicationBatchError("RC-05 terminal summary historical usage drift")
remediation = run["historical_remediation"]
if not isinstance(remediation, list) or len(remediation) != 4:
raise PublicationBatchError("RC-05 historical remediation must cover all four attempts")
remediation_index: dict[str, dict[str, Any]] = {}
for row in remediation:
if not isinstance(row, dict) or row.get("attempt_id") not in attempt_index:
raise PublicationBatchError("RC-05 historical remediation identity drift")
attempt_id = row["attempt_id"]
if attempt_id in remediation_index or row.get("passed") is not True:
raise PublicationBatchError("RC-05 historical remediation is duplicate or not passed")
disposition = attempt_index[attempt_id]["disposition"]
if disposition["release_eligible"]:
if (
row.get("status") != "historically_resolved"
or row.get("replacement_case_id") is not None
or row.get("replacement_operation") is not None
):
raise PublicationBatchError("RC-05 resolved remediation drift")
elif (
row.get("status") != "replacement_verified"
or row.get("replacement_case_id") != disposition["replacement_case_id"]
or row.get("replacement_operation") != disposition["replacement_operation"]
or row.get("provider_passed") is not True
or row.get("business_passed") is not True
or row.get("quality_passed") is not True
or row.get("evidence_error") is not None
):
raise PublicationBatchError("RC-05 replacement remediation is not verified")
remediation_index[attempt_id] = row
if (
set(remediation_index) != set(attempt_index)
or sum(row["status"] == "replacement_verified" for row in remediation) != 3
or sum(row["status"] == "historically_resolved" for row in remediation) != 1
):
raise PublicationBatchError("RC-05 historical remediation status counts drift")
result_rows = run["cases"]
if not isinstance(result_rows, list) or len(result_rows) != 144:
raise PublicationBatchError("RC-05 terminal summary must contain all 144 case results")
plan_cases = {case["case_id"]: case for case in plan["cases"]}
result_cases: dict[str, dict[str, Any]] = {}
for row in result_rows:
if not isinstance(row, dict) or not isinstance(row.get("case_id"), str):
raise PublicationBatchError("RC-05 terminal case result is invalid")
case_id = row["case_id"]
if case_id in result_cases or case_id not in plan_cases:
raise PublicationBatchError("RC-05 terminal case inventory drift")
calls = row.get("provider_call_count")
plan_case = plan_cases[case_id]
minimum_calls = sum(
operation not in {"repair_draft", "repair_review"}
for operation in plan_case["operations"]
)
repair_operations = {
operation for operation in plan_case["operations"]
if operation in {"repair_draft", "repair_review"}
}
allowed_calls = {minimum_calls}
if repair_operations:
if repair_operations != {"repair_draft", "repair_review"}:
raise PublicationBatchError(
f"RC-05 repair operations must be paired: {case_id}"
)
allowed_calls.add(minimum_calls + 2)
if (
row.get("status") != "completed"
or row.get("passed") is not True
or not isinstance(calls, int)
or isinstance(calls, bool)
or calls < 1
or calls > plan_case["provider_call_budget"]
or calls not in allowed_calls
or row.get("automated_quality_passed") is not True
or row.get("automated_model_quality_release_passed") is not True
or row.get("content_quality_release_passed") is not True
or row.get("human_calibration_completed") is not False
or row.get("legal_approval_completed") is not False
):
raise PublicationBatchError(f"RC-05 terminal case is not release-green: {case_id}")
_require_nonnegative_number(
row.get("elapsed_seconds"), f"RC-05 {case_id} elapsed_seconds"
)
result_cases[case_id] = row
if set(result_cases) != set(plan_cases):
raise PublicationBatchError("RC-05 terminal case inventory is incomplete")
coverage = _validate_rc05_case_operation_coverage(
run["case_operation_coverage"],
plan_cases=plan_cases,
result_cases=result_cases,
)
_validate_elapsed_statistics(
run["case_elapsed_seconds"],
"RC-05 case elapsed statistics",
expected_observed=len(result_cases),
)
snapshot = _require_keys(
run["ledger"],
"RC-05 terminal ledger snapshot",
(
"schema_version", "ledger_identity_sha256", "real_provider",
"authority", "budget", "operations", "cases", "campaign",
"attempted", "terminal", "unknown", "provider_terminal",
"release_controls",
),
)
snapshot_attempted = _require_count(
snapshot["attempted"], "RC-05 ledger attempted", maximum=280
)
snapshot_terminal = _require_count(
snapshot["terminal"], "RC-05 ledger terminal", maximum=280
)
snapshot_unknown = _require_count(
snapshot["unknown"], "RC-05 ledger unknown", maximum=280
)
if (
snapshot.get("schema_version") != RC05_LEDGER_SNAPSHOT_SCHEMA_VERSION
or snapshot.get("ledger_identity_sha256") != ledger_identity_sha256
or snapshot.get("real_provider") is not True
or snapshot.get("authority") != authority
or snapshot_unknown != 0
or snapshot_terminal != snapshot_attempted
):
raise PublicationBatchError("RC-05 terminal ledger snapshot identity or terminal counts drift")
control_state = _require_keys(
snapshot.get("release_controls"),
"RC-05 terminal release-control state",
(
"schema_version",
"phase",
"canary_case_ids",
"blocked_failure_classes",
"canary_transition_sha256",
),
)
if (
control_state["schema_version"] != RC05_CONTROL_STATE_SCHEMA_VERSION
or control_state["phase"] != "full_authorized"
or control_state["canary_case_ids"] != list(EXPECTED_RC05_CANARY_CASE_IDS)
or control_state["blocked_failure_classes"] != []
):
raise PublicationBatchError("RC-05 terminal release controls are not green")
_require_sha(
control_state["canary_transition_sha256"],
"RC-05 canary transition SHA-256",
)
case_snapshot = snapshot.get("cases")
operation_snapshot = snapshot.get("operations")
if not isinstance(case_snapshot, dict) or set(case_snapshot) != set(plan_cases):
raise PublicationBatchError("RC-05 ledger case snapshot is incomplete")
if not isinstance(operation_snapshot, dict) or set(operation_snapshot) != set(EXPECTED_RC05_OPERATION_LIMITS):
raise PublicationBatchError("RC-05 ledger operation snapshot is incomplete")
for case_id, plan_case in plan_cases.items():
counts = case_snapshot[case_id]
expected_calls = result_cases[case_id]["provider_call_count"]
if counts != {
"limit": plan_case["provider_call_budget"],
"attempted": expected_calls,
"terminal": expected_calls,
"unknown": 0,
}:
raise PublicationBatchError(f"RC-05 ledger case counts drift: {case_id}")
current_attempted = sum(row["provider_call_count"] for row in result_cases.values())
provider_terminal = _require_count(
snapshot["provider_terminal"],
"RC-05 ledger provider-terminal count",
maximum=280,
)
repair_case_calls = sum(
result_cases[case_id]["provider_call_count"]
- sum(
operation not in {"repair_draft", "repair_review"}
for operation in plan_case["operations"]
)
for case_id, plan_case in plan_cases.items()
)
if (
snapshot_attempted != current_attempted
or provider_terminal != current_attempted
or run["provider_call_count"] != current_attempted
or run["current_plan_provider_call_count"] != current_attempted
or run["provider_call_count_scope"] != "current_plan"
):
raise PublicationBatchError("RC-05 current-plan call count drift")
statistics = run["operation_statistics"]
if not isinstance(statistics, dict) or set(statistics) != set(EXPECTED_RC05_OPERATION_LIMITS):
raise PublicationBatchError("RC-05 operation statistics are incomplete")
historical_attempted = 0
combined_attempted = 0
historical_operation_counts = {operation: 0 for operation in EXPECTED_RC05_OPERATION_LIMITS}
historical_provider_outcomes = {
operation: {"succeeded": 0, "failed": 0, "cancelled": 0, "timeout": 0}
for operation in EXPECTED_RC05_OPERATION_LIMITS
}
historical_business_outcomes = {
operation: {
"succeeded": 0, "failed": 0, "cancelled": 0,
"awaiting_human": 0, "other": 0,
}
for operation in EXPECTED_RC05_OPERATION_LIMITS
}
for attempt in historical_attempts:
operation = attempt["operation"]
historical_operation_counts[operation] += 1
historical_provider_outcomes[operation][attempt["provider_status"]] += 1
if attempt["timed_out"]:
historical_provider_outcomes[operation]["timeout"] += 1
business_status = attempt["business_status"]
business_key = (
"succeeded" if business_status in {"succeeded", "resolved"}
else business_status
if business_status in historical_business_outcomes[operation]
else "other"
)
historical_business_outcomes[operation][business_key] += 1
for operation, limit in EXPECTED_RC05_OPERATION_LIMITS.items():
ledger_counts = operation_snapshot[operation]
stat = _require_keys(
statistics[operation],
f"RC-05 operation statistics {operation}",
(
"limit", "attempted", "terminal", "unknown", "succeeded",
"failed", "cancelled", "awaiting_human", "other", "timeout",
"business_outcomes", "provider_outcomes", "elapsed_seconds",
"historical", "combined",
),
)
attempted = _require_count(
stat.get("attempted"), f"RC-05 {operation} attempted", maximum=limit
)
terminal = _require_count(
stat.get("terminal"), f"RC-05 {operation} terminal", maximum=limit
)
unknown = _require_count(
stat.get("unknown"), f"RC-05 {operation} unknown", maximum=limit
)
succeeded = _require_count(
stat.get("succeeded"), f"RC-05 {operation} succeeded", maximum=limit
)
for field in ("failed", "cancelled", "awaiting_human", "other", "timeout"):
_require_count(stat.get(field), f"RC-05 {operation} {field}", maximum=limit)
for section, keys, maximum in (
(stat.get("business_outcomes"),
("succeeded", "failed", "cancelled", "awaiting_human", "other"), limit),
(stat.get("provider_outcomes"),
("succeeded", "failed", "cancelled", "timeout"), limit),
):
if not isinstance(section, dict) or set(section) != set(keys):
raise PublicationBatchError(
f"RC-05 {operation} outcome fields are incomplete"
)
for key in keys:
_require_count(
section[key], f"RC-05 {operation} outcome {key}", maximum=maximum
)
expected_minimum = 0 if operation in {"repair_draft", "repair_review"} else limit
if attempted < expected_minimum:
raise PublicationBatchError(
f"RC-05 mandatory operation count is incomplete: {operation}"
)
_validate_elapsed_statistics(
stat["elapsed_seconds"],
f"RC-05 {operation} elapsed statistics",
expected_observed=attempted,
)
if not isinstance(stat, dict) or ledger_counts != {
"limit": limit,
"attempted": attempted,
"terminal": terminal,
"unknown": unknown,
}:
raise PublicationBatchError(f"RC-05 operation ledger/statistics drift: {operation}")
if (
stat.get("limit") != limit
or terminal != attempted
or unknown != 0
or succeeded != attempted
or any(stat.get(field) != 0 for field in (
"failed", "cancelled", "awaiting_human", "other", "timeout"
))
or stat.get("business_outcomes") != {
"succeeded": attempted, "failed": 0, "cancelled": 0,
"awaiting_human": 0, "other": 0,
}
or stat.get("provider_outcomes") != {
"succeeded": attempted, "failed": 0, "cancelled": 0, "timeout": 0,
}
):
raise PublicationBatchError(f"RC-05 current operation is not release-green: {operation}")
prior = _require_keys(
stat.get("historical"),
f"RC-05 historical operation statistics {operation}",
(
"attempted", "terminal", "unknown", "provider_outcomes",
"business_outcomes", "elapsed_seconds",
),
)
combined = _require_keys(
stat.get("combined"),
f"RC-05 combined operation statistics {operation}",
(
"attempted", "terminal", "unknown", "provider_outcomes",
"business_outcomes", "elapsed_seconds",
),
)
prior_attempted = _require_count(
prior.get("attempted"), f"RC-05 historical {operation} attempted",
maximum=historical_count,
)
prior_terminal = _require_count(
prior.get("terminal"), f"RC-05 historical {operation} terminal",
maximum=historical_count,
)
prior_unknown = _require_count(
prior.get("unknown"), f"RC-05 historical {operation} unknown",
maximum=historical_count,
)
combined_attempted_value = _require_count(
combined.get("attempted"), f"RC-05 combined {operation} attempted",
maximum=280,
)
combined_terminal = _require_count(
combined.get("terminal"), f"RC-05 combined {operation} terminal",
maximum=280,
)
combined_unknown = _require_count(
combined.get("unknown"), f"RC-05 combined {operation} unknown",
maximum=280,
)
_validate_elapsed_statistics(
prior["elapsed_seconds"],
f"RC-05 historical {operation} elapsed statistics",
expected_observed=prior_attempted,
)
_validate_elapsed_statistics(
combined["elapsed_seconds"],
f"RC-05 combined {operation} elapsed statistics",
expected_observed=combined_attempted_value,
)
for section_name, section, keys in (
("historical provider", prior.get("provider_outcomes"),
("succeeded", "failed", "cancelled", "timeout")),
("historical business", prior.get("business_outcomes"),
("succeeded", "failed", "cancelled", "awaiting_human", "other")),
("combined provider", combined.get("provider_outcomes"),
("succeeded", "failed", "cancelled", "timeout")),
("combined business", combined.get("business_outcomes"),
("succeeded", "failed", "cancelled", "awaiting_human", "other")),
):
if not isinstance(section, dict) or set(section) != set(keys):
raise PublicationBatchError(
f"RC-05 {section_name} outcomes are incomplete: {operation}"
)
for key in keys:
_require_count(
section[key], f"RC-05 {section_name} {operation} {key}", maximum=280
)
if (
prior_attempted != historical_operation_counts[operation]
or prior_terminal != prior_attempted
or prior_unknown != 0
or prior.get("provider_outcomes") != historical_provider_outcomes[operation]
or prior.get("business_outcomes") != historical_business_outcomes[operation]
or combined_attempted_value != attempted + prior_attempted
or combined_terminal != combined_attempted_value
or combined_unknown != 0
or combined.get("provider_outcomes") != {
key: stat["provider_outcomes"][key]
+ historical_provider_outcomes[operation][key]
for key in ("succeeded", "failed", "cancelled", "timeout")
}
or combined.get("business_outcomes") != {
key: stat["business_outcomes"][key]
+ historical_business_outcomes[operation][key]
for key in ("succeeded", "failed", "cancelled", "awaiting_human", "other")
}
):
raise PublicationBatchError(f"RC-05 combined operation counts drift: {operation}")
historical_attempted += prior_attempted
combined_attempted += combined_attempted_value
if historical_attempted != historical_count:
raise PublicationBatchError("RC-05 historical operation statistics are incomplete")
if (
statistics["repair_draft"]["attempted"]
!= statistics["repair_review"]["attempted"]
or repair_case_calls != 2 * statistics["repair_draft"]["attempted"]
):
raise PublicationBatchError("RC-05 repair operation/case counts do not reconcile")
if run["historical_by_operation"] != {
operation: statistics[operation]["historical"]
for operation in EXPECTED_RC05_OPERATION_LIMITS
}:
raise PublicationBatchError("RC-05 historical_by_operation projection drift")
campaign_counts = _require_keys(
snapshot["campaign"],
"RC-05 terminal campaign counts",
(
"attempted", "terminal", "unknown", "provider_terminal",
"current_plan_attempted", "foreign_plan_attempted",
"provider_outcomes",
),
)
campaign_attempted = _require_count(
campaign_counts["attempted"], "RC-05 campaign attempted", maximum=280
)
campaign_terminal = _require_count(
campaign_counts["terminal"], "RC-05 campaign terminal", maximum=280
)
campaign_unknown = _require_count(
campaign_counts["unknown"], "RC-05 campaign unknown", maximum=280
)
campaign_provider_terminal = _require_count(
campaign_counts["provider_terminal"],
"RC-05 campaign provider-terminal count",
maximum=280,
)
campaign_current_plan = _require_count(
campaign_counts["current_plan_attempted"],
"RC-05 campaign current-plan attempted",
maximum=280,
)
campaign_foreign_plan = _require_count(
campaign_counts["foreign_plan_attempted"],
"RC-05 campaign foreign-plan attempted",
maximum=280,
)
campaign_provider_outcomes = _require_keys(
campaign_counts["provider_outcomes"],
"RC-05 campaign provider outcomes",
("succeeded", "failed", "cancelled"),
)
for status, value in campaign_provider_outcomes.items():
_require_count(
value, f"RC-05 campaign provider outcome {status}", maximum=280
)
combined_counts = run["combined_call_counts"]
if (
campaign_attempted != current_attempted
or campaign_terminal != current_attempted
or campaign_unknown != 0
or campaign_provider_terminal != current_attempted
or campaign_provider_terminal != provider_terminal
or campaign_current_plan != current_attempted
or campaign_foreign_plan != 0
or campaign_current_plan + campaign_foreign_plan != campaign_attempted
or campaign_provider_outcomes != {
"succeeded": current_attempted,
"failed": 0,
"cancelled": 0,
}
or run["campaign_new_provider_call_count"] != current_attempted
or combined_counts != {
"attempted": combined_attempted,
"terminal": combined_attempted,
"unknown": 0,
}
or combined_attempted != current_attempted + historical_count
or run["provider_call_count_including_historical"] != combined_attempted
or combined_attempted > 280
):
raise PublicationBatchError(
"RC-05 campaign or combined call statistics drift; the final frozen plan must be "
"the campaign's only new execution plan"
)
budget = snapshot.get("budget")
if (
not isinstance(budget, dict)
or budget.get("provider_call_limit") != 280
or budget.get("historical_provider_call_count") != historical_count
or budget.get("historical_repair_budget_charged") != repair_count
or budget.get("historical_receipt_sha256") != historical_receipt_sha
or budget.get("historical_attempts_sha256") != historical_attempts_sha
):
raise PublicationBatchError("RC-05 ledger budget evidence drift")
return {
"summary_schema_version": RC05_SUMMARY_SCHEMA_VERSION,
"summary_raw_sha256": summary_raw_sha256,
"ledger_identity_raw_sha256": ledger_identity_raw_sha256,
"ledger_identity_sha256": ledger_identity_sha256,
"campaign_identity_raw_sha256": campaign_identity_raw_sha256,
"campaign_identity_sha256": campaign_identity_sha256,
"plan_raw_sha256": plan_sha,
"case_results_sha256": _sha256_json(result_rows),
"operation_statistics_sha256": _sha256_json(statistics),
"case_operation_coverage_sha256": _sha256_json(coverage),
"historical_remediation_sha256": _sha256_json(remediation),
"current_plan_provider_call_count": current_attempted,
"historical_provider_call_count": historical_count,
"combined_provider_call_count": combined_attempted,
"complete_real_green": True,
}
def _historical_attempt_can_be_release_eligible(attempt: Mapping[str, Any]) -> bool:
return (
attempt.get("provider_status") == "succeeded"
and attempt.get("timed_out") is False
and attempt.get("business_status") in {"succeeded", "resolved"}
)
def _empty_disposition(case: Mapping[str, Any]) -> dict[str, Any]:
return {
**case,
"status": "unresolved",
"human_confirmed": False,
"decision_source": None,
"decision_maker": None,
"decided_at": None,
"evidence_sha256": None,
"risk_acceptance": None,
"notes": "",
}
def _validate_decision_maker(value: Any, label: str) -> dict[str, str]:
row = _require_keys(value, label, ("approver_id", "name", "role", "organization"))
normalized = {
field: _require_string(row[field], f"{label}.{field}", max_length=256)
for field in ("approver_id", "name", "role", "organization")
}
stable_identity = {
field: normalized[field]
for field in ("approver_id", "name")
}
if stable_identity != SOLE_RELEASE_REVIEWER:
raise PublicationBatchError("Golden dispositions must use the configured sole release reviewer")
return normalized
def _require_release_reviewer_identity(value: Any, label: str) -> dict[str, str]:
"""Validate human-supplied identity assertions for one exact approval."""
row = _require_keys(value, label, RELEASE_REVIEWER_IDENTITY_FIELDS)
normalized = {
field: _require_string(
row[field],
f"{label}.{field}",
max_length=4000 if field == "authorization_scope" else 256,
)
for field in RELEASE_REVIEWER_IDENTITY_FIELDS
}
stable_identity = {
field: normalized[field]
for field in ("approver_id", "name")
}
if stable_identity != SOLE_RELEASE_REVIEWER:
raise PublicationBatchError(f"{label} must identify the registered sole release reviewer")
return normalized
def validate_disposition(value: Any, case: Mapping[str, Any]) -> dict[str, Any]:
required = (
"sample_id",
"suite",
"asset_id",
"source_case_sha256",
"status",
"human_confirmed",
"decision_source",
"decision_maker",
"decided_at",
"evidence_sha256",
"risk_acceptance",
"notes",
)
row = _require_keys(value, f"Golden disposition {case['sample_id']}", required)
for key in ("sample_id", "suite", "asset_id", "source_case_sha256"):
if row[key] != case[key]:
raise PublicationBatchError(f"Golden disposition identity drift for {case['sample_id']}: {key}")
status_value = row["status"]
if status_value not in DISPOSITION_STATUSES:
raise PublicationBatchError(f"invalid Golden disposition status for {case['sample_id']}")
if not isinstance(row["notes"], str) or len(row["notes"]) > 4000:
raise PublicationBatchError("Golden disposition notes are invalid")
if status_value == "unresolved":
if row["human_confirmed"] is not False:
raise PublicationBatchError("unresolved disposition cannot claim human confirmation")
if any(row[key] is not None for key in (
"decision_source", "decision_maker", "decided_at", "evidence_sha256", "risk_acceptance"
)):
raise PublicationBatchError("unresolved disposition must not contain a decision or evidence")
return dict(row)
if row["human_confirmed"] is not True or row["decision_source"] != "single_reviewer_batch":
raise PublicationBatchError("resolved disposition must be included in the sole reviewer batch")
maker = _validate_decision_maker(row["decision_maker"], "decision maker")
decided = _parse_time(row["decided_at"], "decided_at")
evidence = _require_sha(row["evidence_sha256"], "disposition evidence SHA-256")
if status_value == "named_legal_approval":
if row["risk_acceptance"] is not None:
raise PublicationBatchError("named legal approval must not contain risk acceptance fields")
return {**row, "decision_maker": maker, "evidence_sha256": evidence}
risk = _require_keys(
row["risk_acceptance"],
"risk acceptance",
("owner", "scope", "expires_at", "controls", "use_limits"),
)
owner = _require_string(risk["owner"], "risk acceptance owner", max_length=256)
if owner != SOLE_RELEASE_REVIEWER["name"]:
raise PublicationBatchError("risk acceptance owner must be the configured sole release reviewer")
scope = _require_string(risk["scope"], "risk acceptance scope", max_length=4000)
expires = _parse_time(risk["expires_at"], "risk acceptance expires_at")
if expires <= decided:
raise PublicationBatchError("risk acceptance expiry must be after its decision time")
controls = risk["controls"]
limits = risk["use_limits"]
if not isinstance(controls, list) or not controls or any(not isinstance(item, str) or not item.strip() for item in controls):
raise PublicationBatchError("risk acceptance controls must be a non-empty string list")
if not isinstance(limits, list) or not limits or any(not isinstance(item, str) or not item.strip() for item in limits):
raise PublicationBatchError("risk acceptance use_limits must be a non-empty string list")
return {
**row,
"decision_maker": maker,
"evidence_sha256": evidence,
"risk_acceptance": {
"owner": owner,
"scope": scope,
"expires_at": risk["expires_at"],
"controls": [item.strip() for item in controls],
"use_limits": [item.strip() for item in limits],
},
}
def build_dispositions(golden_cases: list[dict[str, Any]], source: Any | None) -> list[dict[str, Any]]:
expected = {item["sample_id"]: item for item in golden_cases}
if source is None:
return [_empty_disposition(expected[key]) for key in sorted(expected)]
document = _require_keys(source, "Golden dispositions", ("schema_version", "items"))
if document["schema_version"] != DISPOSITION_SCHEMA_VERSION or not isinstance(document["items"], list):
raise PublicationBatchError("unsupported Golden disposition document")
supplied: dict[str, Any] = {}
for row in document["items"]:
if not isinstance(row, dict) or not isinstance(row.get("sample_id"), str):
raise PublicationBatchError("Golden disposition item is invalid")
if row["sample_id"] in supplied:
raise PublicationBatchError(f"duplicate Golden disposition: {row['sample_id']}")
supplied[row["sample_id"]] = row
if set(supplied) != set(expected):
raise PublicationBatchError(
f"Golden disposition inventory mismatch; missing={sorted(set(expected)-set(supplied))}, "
f"extra={sorted(set(supplied)-set(expected))}"
)
return [validate_disposition(supplied[key], expected[key]) for key in sorted(expected)]
def assemble_manifest(
*,
commit: str,
tag: str,
source_manifest_sha256: str,
source_manifest_payload_sha256: str | None,
image_identities_sha256: str,
image_identity: dict[str, Any],
rc05_plan_sha256: str,
rc05_plan_identity: dict[str, Any],
rc05_terminal_evidence: dict[str, Any],
inventory: dict[str, Any],
dispositions: list[dict[str, Any]],
) -> dict[str, Any]:
unresolved = sum(item["status"] == "unresolved" for item in dispositions)
disposition_counts = {
status_value: sum(item["status"] == status_value for item in dispositions)
for status_value in sorted(DISPOSITION_STATUSES)
}
manifest: dict[str, Any] = {
"schema_version": SCHEMA_VERSION,
"candidate": {
"commit": commit,
"tag": tag,
"source_manifest_sha256": _require_sha(source_manifest_sha256, "source manifest SHA-256"),
"source_manifest_payload_sha256": (
_require_sha(source_manifest_payload_sha256, "source manifest payload SHA-256")
if source_manifest_payload_sha256 is not None
else None
),
"image_identities_sha256": _require_sha(image_identities_sha256, "image identities SHA-256"),
"image_identity_set_sha256": image_identity["identity_set_sha256"],
"images": image_identity["images"],
"rc05_plan_sha256": _require_sha(rc05_plan_sha256, "RC-05 plan SHA-256"),
"rc05_plan_identity": rc05_plan_identity,
"rc05_terminal_evidence": rc05_terminal_evidence,
},
"asset_batch": {
"count": len(inventory["assets"]),
"items": inventory["assets"],
"inventory_sha256": _sha256_json(inventory["assets"]),
},
"prompt_module_batch": {
"count": len(inventory["prompt_modules"]),
"drafting_count": sum(item["category"] == "drafting" for item in inventory["prompt_modules"]),
"review_count": sum(item["category"] == "review" for item in inventory["prompt_modules"]),
"drafting_prompt_keys": ["contract_drafting"],
"review_routes": sorted(
item["publication_mapping"]["route"]
for item in inventory["prompt_modules"]
if item["category"] == "review"
),
"items": inventory["prompt_modules"],
"inventory_sha256": _sha256_json(inventory["prompt_modules"]),
},
"runtime_prompt_dependencies": {
"publication_item_count": EXPECTED_ASSET_COUNT + EXPECTED_MODULE_COUNT,
"count": len(inventory["runtime_prompt_dependencies"]),
"items": inventory["runtime_prompt_dependencies"],
"inventory_sha256": _sha256_json(inventory["runtime_prompt_dependencies"]),
},
"default_prompt_asset_boundary": inventory["default_prompt_boundary"],
"golden_dispositions": {
"count": len(dispositions),
"counts_by_status": disposition_counts,
"items": dispositions,
"inventory_sha256": _sha256_json(dispositions),
},
"publication_control": {
"rc05_terminal_evidence_complete": rc05_terminal_evidence.get("complete_real_green") is True,
"golden_dispositions_complete": unresolved == 0,
"approval_receipt_attached": False,
"apply_receipt_attached": False,
"single_reviewer_batch_and_system_item_receipts_complete": False,
"runtime_executable_prompt_snapshots_complete": False,
"blocked_controls": list(BLOCKED_CONTROLS),
"release_ready": False,
"approval_receipt_schema": APPROVAL_SCHEMA_VERSION,
"apply_receipt_schema": APPLY_SCHEMA_VERSION,
"apply_performed_by_this_tool": False,
},
"side_effects": {
"http_calls": 0,
"database_writes": 0,
"model_calls": 0,
"publication_api_calls": 0,
},
"claims_not_made": [
"This offline manifest is not legal approval and does not fabricate a signature.",
"This offline manifest does not authorize or perform publication.",
"The separate 46 default Prompt assets are not included in the 14-module batch.",
"No reviewer approval or apply evidence is embedded in this offline manifest.",
"One signed batch approval must bind all 60 assets, 14 Prompt modules, and 31 dispositions.",
"The apply service must emit 74 machine-verifiable item results and online hashes.",
"One composed drafting plus thirteen review runtime Prompt snapshots are not implemented and remain blocking.",
],
}
_assert_no_secret_material(manifest)
manifest["manifest_payload_sha256"] = _sha256_json(manifest)
return manifest
def _validate_asset(asset: Any) -> None:
if not isinstance(asset, dict):
raise PublicationBatchError("asset item must be an object")
required = {
"template_id", "name", "version", "document_kind", "contract_type", "source",
"source_lifecycle_status", "body_content", "content_sha256", "input_schema",
"required_variables", "optional_variables", "validation_rules", "clause_ids",
"review_rule_ids", "review_identity", "body_sha256", "input_schema_sha256",
"variables_sha256", "review_identity_sha256", "asset_payload_sha256",
}
if set(asset) != required:
raise PublicationBatchError(f"asset {asset.get('template_id')} field set drift")
template_id = _require_string(asset["template_id"], "template ID", max_length=128)
if not STABLE_ID_RE.fullmatch(template_id):
raise PublicationBatchError(f"asset ID is invalid: {template_id}")
if not isinstance(asset["body_content"], str) or not asset["body_content"]:
raise PublicationBatchError(f"asset body is empty: {template_id}")
if _sha256_bytes(asset["body_content"].encode("utf-8")) != asset["body_sha256"]:
raise PublicationBatchError(f"asset body hash drift: {template_id}")
schema_hash = _sha256_json(asset["input_schema"]) if asset["input_schema"] is not None else None
if schema_hash != asset["input_schema_sha256"]:
raise PublicationBatchError(f"asset input schema hash drift: {template_id}")
variable_hash = _sha256_json(
{"required": asset["required_variables"], "optional": asset["optional_variables"]}
)
if variable_hash != asset["variables_sha256"]:
raise PublicationBatchError(f"asset variable hash drift: {template_id}")
if _sha256_json(asset["review_identity"]) != asset["review_identity_sha256"]:
raise PublicationBatchError(f"asset review identity hash drift: {template_id}")
if _sha256_json(_asset_hash_projection(asset)) != asset["content_sha256"]:
raise PublicationBatchError(f"asset content hash drift: {template_id}")
payload = {key: value for key, value in asset.items() if key != "asset_payload_sha256"}
if _sha256_json(payload) != asset["asset_payload_sha256"]:
raise PublicationBatchError(f"asset payload hash drift: {template_id}")
def _validate_prompt_module(module: Any) -> None:
row = _require_keys(
module,
"Prompt module",
("category", "key", "version", "content", "content_sha256", "publication_mapping", "module_payload_sha256"),
)
if row["category"] not in {"drafting", "review"}:
raise PublicationBatchError("Prompt module category is invalid")
key = _require_string(row["key"], "Prompt module key", max_length=128)
if not isinstance(row["content"], str) or not row["content"]:
raise PublicationBatchError(f"Prompt module content is empty: {key}")
if _sha256_bytes(row["content"].encode("utf-8")) != row["content_sha256"]:
raise PublicationBatchError(f"Prompt module content hash drift: {key}")
mapping = _require_keys(row["publication_mapping"], "Prompt module mapping", ("prompt_key", "route"))
if row["category"] == "drafting" and mapping != {"prompt_key": "contract_drafting", "route": "contract_drafting"}:
raise PublicationBatchError("all drafting modules must map to the one contract_drafting Prompt")
if row["category"] == "review" and mapping != {"prompt_key": key, "route": key}:
raise PublicationBatchError("review module must map one-to-one to its review route")
payload = {name: value for name, value in row.items() if name != "module_payload_sha256"}
if _sha256_json(payload) != row["module_payload_sha256"]:
raise PublicationBatchError(f"Prompt module payload hash drift: {key}")
def validate_manifest(payload: Any) -> dict[str, Any]:
manifest = _require_keys(
payload,
"publication batch",
(
"schema_version", "candidate", "asset_batch", "prompt_module_batch",
"runtime_prompt_dependencies", "default_prompt_asset_boundary",
"golden_dispositions", "publication_control",
"side_effects", "claims_not_made", "manifest_payload_sha256",
),
)
if manifest["schema_version"] != SCHEMA_VERSION:
raise PublicationBatchError("unsupported publication batch schema")
expected_payload_hash = manifest["manifest_payload_sha256"]
_require_sha(expected_payload_hash, "publication batch payload SHA-256")
projection = {key: value for key, value in manifest.items() if key != "manifest_payload_sha256"}
if _sha256_json(projection) != expected_payload_hash:
raise PublicationBatchError("publication batch canonical hash drift")
candidate = _require_keys(
manifest["candidate"],
"candidate",
(
"commit", "tag", "source_manifest_sha256", "source_manifest_payload_sha256",
"image_identities_sha256", "image_identity_set_sha256", "images",
"rc05_plan_sha256", "rc05_plan_identity", "rc05_terminal_evidence",
),
)
if not COMMIT_RE.fullmatch(str(candidate["commit"])) or not TAG_RE.fullmatch(str(candidate["tag"])):
raise PublicationBatchError("candidate commit or tag is invalid")
for key in ("source_manifest_sha256", "image_identities_sha256", "image_identity_set_sha256", "rc05_plan_sha256"):
_require_sha(candidate[key], f"candidate.{key}")
if candidate["source_manifest_payload_sha256"] is not None:
_require_sha(candidate["source_manifest_payload_sha256"], "candidate.source_manifest_payload_sha256")
image_check = validate_image_identities(
{
"schema_version": IMAGE_SCHEMA_VERSION,
"commit": candidate["commit"],
"tag": candidate["tag"],
"images": candidate["images"],
},
candidate["commit"],
candidate["tag"],
)
if image_check["identity_set_sha256"] != candidate["image_identity_set_sha256"]:
raise PublicationBatchError("image identity set hash drift")
validate_rc05_plan_identity(candidate["rc05_plan_identity"])
terminal = _require_keys(
candidate["rc05_terminal_evidence"],
"RC-05 terminal evidence identity",
(
"summary_schema_version", "summary_raw_sha256",
"ledger_identity_raw_sha256", "ledger_identity_sha256",
"campaign_identity_raw_sha256", "campaign_identity_sha256",
"plan_raw_sha256", "case_results_sha256", "operation_statistics_sha256",
"case_operation_coverage_sha256", "historical_remediation_sha256",
"current_plan_provider_call_count", "historical_provider_call_count",
"combined_provider_call_count", "complete_real_green",
),
)
for key in (
"summary_raw_sha256", "ledger_identity_raw_sha256", "ledger_identity_sha256",
"campaign_identity_raw_sha256", "campaign_identity_sha256", "plan_raw_sha256",
"case_results_sha256", "operation_statistics_sha256",
"case_operation_coverage_sha256", "historical_remediation_sha256",
):
_require_sha(terminal[key], f"RC-05 terminal evidence {key}")
current_plan_calls = _require_count(
terminal["current_plan_provider_call_count"],
"RC-05 terminal current-plan provider calls",
maximum=276,
)
historical_calls = _require_count(
terminal["historical_provider_call_count"],
"RC-05 terminal historical provider calls",
maximum=280,
)
combined_calls = _require_count(
terminal["combined_provider_call_count"],
"RC-05 terminal combined provider calls",
maximum=280,
)
if (
terminal["summary_schema_version"] != RC05_SUMMARY_SCHEMA_VERSION
or terminal["plan_raw_sha256"] != candidate["rc05_plan_sha256"]
or terminal["complete_real_green"] is not True
or current_plan_calls < 264
or historical_calls != 4
or combined_calls != current_plan_calls + historical_calls
):
raise PublicationBatchError("RC-05 terminal evidence identity drift")
assets = manifest["asset_batch"]
if not isinstance(assets, dict) or set(assets) != {"count", "items", "inventory_sha256"}:
raise PublicationBatchError("asset batch shape is invalid")
if assets["count"] != EXPECTED_ASSET_COUNT or not isinstance(assets["items"], list) or len(assets["items"]) != EXPECTED_ASSET_COUNT:
raise PublicationBatchError("asset batch must contain exactly 60 assets")
for item in assets["items"]:
_validate_asset(item)
asset_ids = [item["template_id"] for item in assets["items"]]
if len(set(asset_ids)) != EXPECTED_ASSET_COUNT:
raise PublicationBatchError("asset batch contains duplicate template IDs")
if _sha256_json(assets["items"]) != assets["inventory_sha256"]:
raise PublicationBatchError("asset inventory hash drift")
modules = manifest["prompt_module_batch"]
expected_module_keys = {
"count", "drafting_count", "review_count", "drafting_prompt_keys",
"review_routes", "items", "inventory_sha256",
}
if not isinstance(modules, dict) or set(modules) != expected_module_keys:
raise PublicationBatchError("Prompt module batch shape is invalid")
if (
modules["count"] != EXPECTED_MODULE_COUNT
or modules["drafting_count"] != EXPECTED_DRAFTING_MODULE_COUNT
or modules["review_count"] != EXPECTED_REVIEW_MODULE_COUNT
or modules["drafting_prompt_keys"] != ["contract_drafting"]
or not isinstance(modules["items"], list)
or len(modules["items"]) != EXPECTED_MODULE_COUNT
):
raise PublicationBatchError("Prompt module counts or drafting mapping drift")
for item in modules["items"]:
_validate_prompt_module(item)
module_keys = [item["key"] for item in modules["items"]]
if len(set(module_keys)) != EXPECTED_MODULE_COUNT:
raise PublicationBatchError("Prompt module batch contains duplicate keys")
review_routes = sorted(
item["key"] for item in modules["items"] if item["category"] == "review"
)
if modules["review_routes"] != review_routes or len(review_routes) != EXPECTED_REVIEW_MODULE_COUNT:
raise PublicationBatchError("review route inventory drift")
if _sha256_json(modules["items"]) != modules["inventory_sha256"]:
raise PublicationBatchError("Prompt module inventory hash drift")
runtime = _require_keys(
manifest["runtime_prompt_dependencies"],
"runtime Prompt dependencies",
("publication_item_count", "count", "items", "inventory_sha256"),
)
if (
runtime["publication_item_count"] != EXPECTED_ASSET_COUNT + EXPECTED_MODULE_COUNT
or runtime["count"] != EXPECTED_RUNTIME_PROMPT_COUNT
or not isinstance(runtime["items"], list)
or len(runtime["items"]) != EXPECTED_RUNTIME_PROMPT_COUNT
):
raise PublicationBatchError(
"runtime Prompt dependencies must distinguish 74 publication items from 14 snapshots"
)
runtime_keys: set[str] = set()
runtime_kinds: list[str] = []
runtime_keys_by_kind: dict[str, set[str]] = {}
publication_modules = {
item["key"]: {
"key": item["key"],
"version": item["version"],
"content_sha256": item["content_sha256"],
}
for item in modules["items"]
}
for item in runtime["items"]:
row = _require_keys(
item,
"runtime Prompt dependency",
(
"kind",
"runtime_key",
"version",
"content_sha256",
"publication_dependency",
"publication_module_dependencies",
),
)
key = _require_string(row["runtime_key"], "runtime Prompt key", max_length=128)
_require_string(row["version"], f"runtime Prompt {key} version", max_length=128)
_require_sha(row["content_sha256"], f"runtime Prompt {key} content SHA-256")
if key in runtime_keys:
raise PublicationBatchError("runtime Prompt dependency keys must be unique")
runtime_keys.add(key)
runtime_kinds.append(row["kind"])
runtime_keys_by_kind.setdefault(row["kind"], set()).add(key)
expected_dependency = {
"composed_drafting": "six_module_composition",
"new_review_module": "published_module",
"existing_domain_prompt": "preexisting_domain_prompt",
}.get(row["kind"])
if row["publication_dependency"] != expected_dependency:
raise PublicationBatchError(f"runtime Prompt dependency kind drift: {key}")
dependency_rows = row["publication_module_dependencies"]
if not isinstance(dependency_rows, list):
raise PublicationBatchError(
f"runtime Prompt module dependencies must be a list: {key}"
)
if row["kind"] == "composed_drafting":
expected_module_keys = list(DRAFTING_RUNTIME_MODULE_ORDER)
elif row["kind"] == "new_review_module":
expected_module_keys = [key]
else:
expected_module_keys = []
expected_dependency_rows = [
publication_modules[module_key] for module_key in expected_module_keys
]
if dependency_rows != expected_dependency_rows:
raise PublicationBatchError(
f"runtime Prompt is not bound to exact publication module identities: {key}"
)
if (
runtime_kinds.count("composed_drafting") != 1
or runtime_kinds.count("new_review_module") != 8
or runtime_kinds.count("existing_domain_prompt") != 5
or runtime_keys_by_kind.get("composed_drafting") != {"contract_drafting_v1"}
or runtime_keys_by_kind.get("new_review_module") != set(review_routes)
or runtime_keys_by_kind.get("existing_domain_prompt")
!= set(RUNTIME_EXISTING_DOMAIN_PROMPTS)
):
raise PublicationBatchError("runtime Prompt dependency 1+8+5 inventory drift")
if _sha256_json(runtime["items"]) != runtime["inventory_sha256"]:
raise PublicationBatchError("runtime Prompt dependency inventory hash drift")
boundary = manifest["default_prompt_asset_boundary"]
required_boundary = {
"included_in_publication_batch", "count", "source_path", "source_raw_sha256",
"inventory", "inventory_sha256", "boundary_note",
}
if not isinstance(boundary, dict) or set(boundary) != required_boundary:
raise PublicationBatchError("default Prompt boundary shape is invalid")
if boundary["included_in_publication_batch"] is not False or boundary["count"] != EXPECTED_DEFAULT_PROMPT_COUNT:
raise PublicationBatchError("46 default Prompt assets must remain outside this batch")
if not isinstance(boundary["inventory"], list) or len(boundary["inventory"]) != EXPECTED_DEFAULT_PROMPT_COUNT:
raise PublicationBatchError("default Prompt boundary inventory count drift")
default_keys = [item.get("prompt_key") for item in boundary["inventory"] if isinstance(item, dict)]
if len(default_keys) != EXPECTED_DEFAULT_PROMPT_COUNT or len(set(default_keys)) != EXPECTED_DEFAULT_PROMPT_COUNT:
raise PublicationBatchError("default Prompt boundary contains duplicate or invalid keys")
if set(default_keys).intersection(module_keys):
raise PublicationBatchError("14 modules overlap the separate 46 default Prompt assets")
if _sha256_json(boundary["inventory"]) != boundary["inventory_sha256"]:
raise PublicationBatchError("default Prompt boundary hash drift")
golden = manifest["golden_dispositions"]
if not isinstance(golden, dict) or set(golden) != {"count", "counts_by_status", "items", "inventory_sha256"}:
raise PublicationBatchError("Golden disposition section is invalid")
if golden["count"] != EXPECTED_GOLDEN_COUNT or not isinstance(golden["items"], list) or len(golden["items"]) != EXPECTED_GOLDEN_COUNT:
raise PublicationBatchError("all 31 Golden dispositions must be present")
cases = {
item["sample_id"]: {
"sample_id": item["sample_id"],
"suite": item["suite"],
"asset_id": item["asset_id"],
"source_case_sha256": item["source_case_sha256"],
}
for item in golden["items"]
if isinstance(item, dict) and isinstance(item.get("sample_id"), str)
}
if len(cases) != EXPECTED_GOLDEN_COUNT:
raise PublicationBatchError("Golden dispositions contain duplicate sample IDs")
validated = [validate_disposition(item, cases[item["sample_id"]]) for item in golden["items"]]
if validated != golden["items"]:
raise PublicationBatchError("Golden dispositions are not normalized")
actual_counts = {
status_value: sum(item["status"] == status_value for item in golden["items"])
for status_value in sorted(DISPOSITION_STATUSES)
}
if golden["counts_by_status"] != actual_counts or _sha256_json(golden["items"]) != golden["inventory_sha256"]:
raise PublicationBatchError("Golden disposition count or hash drift")
suite_counts = {
"contract_generation": sum(item["suite"] == "contract_generation" for item in golden["items"]),
"clause_recommendation": sum(item["suite"] == "clause_recommendation" for item in golden["items"]),
}
if suite_counts != {
"contract_generation": EXPECTED_GOLDEN_GENERATION_COUNT,
"clause_recommendation": EXPECTED_GOLDEN_CLAUSE_COUNT,
}:
raise PublicationBatchError("Golden suite counts drift")
control = manifest["publication_control"]
expected_control_keys = {
"rc05_terminal_evidence_complete", "golden_dispositions_complete",
"approval_receipt_attached", "apply_receipt_attached",
"single_reviewer_batch_and_system_item_receipts_complete",
"runtime_executable_prompt_snapshots_complete", "blocked_controls",
"release_ready", "approval_receipt_schema", "apply_receipt_schema",
"apply_performed_by_this_tool",
}
if not isinstance(control, dict) or set(control) != expected_control_keys:
raise PublicationBatchError("publication control shape is invalid")
complete = actual_counts["unresolved"] == 0
if (
control["golden_dispositions_complete"] is not complete
or control["rc05_terminal_evidence_complete"] is not True
or control["approval_receipt_attached"] is not False
or control["apply_receipt_attached"] is not False
or control["single_reviewer_batch_and_system_item_receipts_complete"] is not False
or control["runtime_executable_prompt_snapshots_complete"] is not False
or control["blocked_controls"] != list(BLOCKED_CONTROLS)
or control["release_ready"] is not False
or control["apply_performed_by_this_tool"] is not False
or control["approval_receipt_schema"] != APPROVAL_SCHEMA_VERSION
or control["apply_receipt_schema"] != APPLY_SCHEMA_VERSION
):
raise PublicationBatchError("offline manifest must remain fail-closed and unapplied")
if manifest["side_effects"] != {
"http_calls": 0,
"database_writes": 0,
"model_calls": 0,
"publication_api_calls": 0,
}:
raise PublicationBatchError("offline side-effect boundary drift")
_assert_no_secret_material(manifest)
return manifest
def build_approval_review_summary(
payload: Any,
*,
manifest_raw_sha256: str,
reviewer: Any,
) -> dict[str, Any]:
"""Build the exact, human-readable projection approved by the sole reviewer."""
manifest = validate_manifest(payload)
reviewer_identity = _require_release_reviewer_identity(
reviewer,
"approval review identity",
)
candidate = manifest["candidate"]
terminal = candidate["rc05_terminal_evidence"]
manifest_raw_sha256 = _require_sha(
manifest_raw_sha256,
"publication batch raw SHA-256",
)
summary = {
"schema_version": APPROVAL_REVIEW_SUMMARY_SCHEMA_VERSION,
"decision_scope": "approve_exact_rc06_publication_batch",
"reviewer": reviewer_identity,
"candidate": {
"commit": candidate["commit"],
"tag": candidate["tag"],
"source_manifest_sha256": candidate["source_manifest_sha256"],
"source_manifest_payload_sha256": candidate["source_manifest_payload_sha256"],
"image_identities_sha256": candidate["image_identities_sha256"],
"image_identity_set_sha256": candidate["image_identity_set_sha256"],
"rc05_plan_sha256": candidate["rc05_plan_sha256"],
"rc05_summary_raw_sha256": terminal["summary_raw_sha256"],
"rc05_ledger_identity_raw_sha256": terminal["ledger_identity_raw_sha256"],
"rc05_campaign_identity_raw_sha256": terminal["campaign_identity_raw_sha256"],
"rc05_complete_real_green": terminal["complete_real_green"],
},
"batch": {
"asset_count": manifest["asset_batch"]["count"],
"asset_inventory_sha256": manifest["asset_batch"]["inventory_sha256"],
"prompt_module_count": manifest["prompt_module_batch"]["count"],
"prompt_module_inventory_sha256": manifest["prompt_module_batch"]["inventory_sha256"],
"golden_disposition_count": manifest["golden_dispositions"]["count"],
"golden_disposition_counts_by_status": manifest["golden_dispositions"]["counts_by_status"],
"golden_disposition_inventory_sha256": manifest["golden_dispositions"]["inventory_sha256"],
},
"manifest_raw_sha256": manifest_raw_sha256,
"manifest_payload_sha256": manifest["manifest_payload_sha256"],
"approval_validity_max_hours": int(MAX_APPROVAL_WINDOW.total_seconds() // 3600),
"remaining_controls_after_approval": list(BLOCKED_CONTROLS[1:]),
"claims_not_made": [
"This approval does not itself publish any asset or Prompt module.",
"This approval does not authorize public production traffic cutover.",
"System apply evidence and executable runtime Prompt snapshots remain separate gates.",
],
}
_assert_no_secret_material(summary, "approval review summary")
return summary
def _approval_risk_acceptance_deadline(manifest: Mapping[str, Any]) -> datetime | None:
"""Return the earliest expiry across scoped Golden risk acceptances."""
deadlines = [
_parse_time(
item["risk_acceptance"]["expires_at"],
f"Golden disposition {item['sample_id']} risk acceptance expires_at",
)
for item in manifest["golden_dispositions"]["items"]
if item["status"] == "scoped_internal_risk_acceptance"
]
return min(deadlines) if deadlines else None
def _validate_disposition_approval_window(
manifest: Mapping[str, Any],
*,
approved_at: datetime,
expires_at: datetime,
) -> None:
"""Ensure every disposition decision and exception covers the approval window."""
for item in manifest["golden_dispositions"]["items"]:
if item["status"] == "unresolved":
raise PublicationBatchError(
"approval cannot release a batch with unresolved Golden dispositions"
)
decided_at = _parse_time(
item["decided_at"],
f"Golden disposition {item['sample_id']} decided_at",
)
if decided_at > approved_at:
raise PublicationBatchError(
f"Golden disposition {item['sample_id']} was decided after the approval time"
)
if item["status"] != "scoped_internal_risk_acceptance":
continue
risk_expires_at = _parse_time(
item["risk_acceptance"]["expires_at"],
f"Golden disposition {item['sample_id']} risk acceptance expires_at",
)
if approved_at >= risk_expires_at:
raise PublicationBatchError(
f"Golden disposition {item['sample_id']} risk acceptance expired before approval"
)
if expires_at > risk_expires_at:
raise PublicationBatchError(
f"approval validity exceeds Golden disposition {item['sample_id']} risk acceptance"
)
def build_approval_payload(
manifest: Any,
*,
manifest_raw_sha256: str,
key_id: str,
approval_keyring_epoch: int,
approval_keyring_payload_sha256: str,
approved_at: datetime,
expires_at: datetime,
approver: Any,
) -> dict[str, Any]:
"""Build the only approval payload accepted for the exact validated batch."""
validated = validate_manifest(manifest)
normalized_key_id = _require_string(key_id, "approval key_id", max_length=128)
if not STABLE_ID_RE.fullmatch(normalized_key_id):
raise PublicationBatchError("approval key_id is invalid")
if (
not isinstance(approval_keyring_epoch, int)
or isinstance(approval_keyring_epoch, bool)
or approval_keyring_epoch < 1
):
raise PublicationBatchError("approval keyring epoch is invalid")
normalized_keyring_payload_sha256 = _require_sha(
approval_keyring_payload_sha256,
"approval keyring payload SHA-256",
)
if approved_at.tzinfo is None or approved_at.utcoffset() is None:
raise PublicationBatchError("approval approved_at must include a timezone")
if expires_at.tzinfo is None or expires_at.utcoffset() is None:
raise PublicationBatchError("approval expires_at must include a timezone")
if expires_at <= approved_at or expires_at - approved_at > MAX_APPROVAL_WINDOW:
raise PublicationBatchError(
"approval validity must be greater than zero and no longer than seven days"
)
if not validated["publication_control"]["golden_dispositions_complete"]:
raise PublicationBatchError("approval cannot release a batch with unresolved Golden dispositions")
_validate_disposition_approval_window(
validated,
approved_at=approved_at,
expires_at=expires_at,
)
manifest_raw_sha256 = _require_sha(
manifest_raw_sha256,
"publication batch raw SHA-256",
)
confirmed_approver = _require_sole_release_reviewer(
approver,
"approval approver",
)
reviewer_identity = {
field: confirmed_approver[field]
for field in RELEASE_REVIEWER_IDENTITY_FIELDS
}
review_summary = build_approval_review_summary(
validated,
manifest_raw_sha256=manifest_raw_sha256,
reviewer=reviewer_identity,
)
return {
"schema_version": APPROVAL_PAYLOAD_SCHEMA_VERSION,
"batch_manifest_raw_sha256": manifest_raw_sha256,
"batch_manifest_payload_sha256": validated["manifest_payload_sha256"],
"decision": "approved",
"approved_at": approved_at.isoformat(timespec="seconds"),
"expires_at": expires_at.isoformat(timespec="seconds"),
"key_id": normalized_key_id,
"approval_keyring_epoch": approval_keyring_epoch,
"approval_keyring_payload_sha256": normalized_keyring_payload_sha256,
"approver": confirmed_approver,
"asset_payload_sha256s": {
item["template_id"]: item["asset_payload_sha256"]
for item in validated["asset_batch"]["items"]
},
"prompt_module_payload_sha256s": {
item["key"]: item["module_payload_sha256"]
for item in validated["prompt_module_batch"]["items"]
},
"golden_disposition_inventory_sha256": validated["golden_dispositions"][
"inventory_sha256"
],
"review_summary_sha256": _sha256_json(review_summary),
}
def _require_sole_release_reviewer(value: Any, label: str) -> dict[str, Any]:
reviewer = _require_keys(
value,
label,
(*RELEASE_REVIEWER_IDENTITY_FIELDS, "human_confirmed"),
)
identity = _require_release_reviewer_identity(
{field: reviewer[field] for field in RELEASE_REVIEWER_IDENTITY_FIELDS},
label,
)
if reviewer["human_confirmed"] is not True:
raise PublicationBatchError("AI or automated self-approval is forbidden")
return {**identity, "human_confirmed": reviewer["human_confirmed"]}
def _public_key_raw(public_key: Ed25519PublicKey) -> bytes:
return public_key.public_bytes(
serialization.Encoding.Raw,
serialization.PublicFormat.Raw,
)
def _public_key_spki(public_key: Any) -> bytes:
try:
return public_key.public_bytes(
serialization.Encoding.DER,
serialization.PublicFormat.SubjectPublicKeyInfo,
)
except (AttributeError, TypeError, ValueError) as exc:
raise PublicationBatchError("online signing public key is invalid") from exc
def _read_pinned_spki_public_key(path: Path, *, expected_sha256: str, label: str) -> Any:
if not HEX64_RE.fullmatch(expected_sha256):
raise PublicationBatchError(f"{label} SPKI pin is not provisioned in the frozen source")
raw = secure_read_bytes(path, label, maximum_bytes=64 * 1024)
try:
public_key = serialization.load_pem_public_key(raw)
except (TypeError, ValueError) as exc:
raise PublicationBatchError(f"{label} is not a valid PEM public key") from exc
if not isinstance(public_key, (rsa.RSAPublicKey, ec.EllipticCurvePublicKey)):
raise PublicationBatchError(f"{label} must be an RSA or EC KMS signing key")
if _sha256_bytes(_public_key_spki(public_key)) != expected_sha256:
raise PublicationBatchError(f"{label} does not match the frozen SPKI trust anchor")
return public_key
def _verify_frozen_kms_signature(
public_key: Any,
signature_block: Any,
*,
domain: bytes,
payload: Mapping[str, Any],
label: str,
include_request_id: bool,
) -> tuple[dict[str, Any], bytes]:
"""Verify one KMS digest signature against exact frozen signer metadata."""
fields = (
"provider",
"key_reference",
"key_version",
"algorithm",
"value_base64",
) + (("request_id",) if include_request_id else ())
signature = _require_keys(
signature_block,
f"{label} signature",
fields,
)
required_trust = (
TRUSTED_ONLINE_APPLY_SERVICE_PROVIDER,
TRUSTED_ONLINE_APPLY_SERVICE_KEY_REFERENCE,
TRUSTED_ONLINE_APPLY_SERVICE_KEY_VERSION,
TRUSTED_ONLINE_APPLY_SERVICE_ALGORITHM,
TRUSTED_ONLINE_APPLY_SERVICE_PUBLIC_KEY_SPKI_SHA256,
)
if (
not all(isinstance(value, str) and value for value in required_trust)
or not HEX64_RE.fullmatch(
TRUSTED_ONLINE_APPLY_SERVICE_PUBLIC_KEY_SPKI_SHA256
)
):
raise PublicationBatchError("online KMS signer trust is not fully provisioned")
if (
signature["provider"] != TRUSTED_ONLINE_APPLY_SERVICE_PROVIDER
or signature["key_reference"]
!= TRUSTED_ONLINE_APPLY_SERVICE_KEY_REFERENCE
or signature["key_version"] != TRUSTED_ONLINE_APPLY_SERVICE_KEY_VERSION
or signature["algorithm"] != TRUSTED_ONLINE_APPLY_SERVICE_ALGORITHM
):
raise PublicationBatchError(f"{label} KMS signer identity drift")
if include_request_id:
_require_string(
signature["request_id"], f"{label} KMS request_id", max_length=512
)
if (
_sha256_bytes(_public_key_spki(public_key))
!= TRUSTED_ONLINE_APPLY_SERVICE_PUBLIC_KEY_SPKI_SHA256
):
raise PublicationBatchError(f"{label} signer does not match the frozen SPKI pin")
try:
signature_bytes = base64.b64decode(
_require_string(
signature["value_base64"], f"{label} signature value", max_length=16384
),
validate=True,
)
digest = hashlib.sha256(domain + _canonical(payload)).digest()
algorithm = signature["algorithm"]
if algorithm == "RSA_PSS_SHA_256" and isinstance(public_key, rsa.RSAPublicKey):
public_key.verify(
signature_bytes,
digest,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=hashes.SHA256().digest_size,
),
utils.Prehashed(hashes.SHA256()),
)
elif algorithm == "RSA_PKCS1_SHA_256" and isinstance(
public_key, rsa.RSAPublicKey
):
public_key.verify(
signature_bytes,
digest,
padding.PKCS1v15(),
utils.Prehashed(hashes.SHA256()),
)
elif algorithm == "ECDSA_SHA_256" and isinstance(
public_key, ec.EllipticCurvePublicKey
):
public_key.verify(
signature_bytes,
digest,
ec.ECDSA(utils.Prehashed(hashes.SHA256())),
)
else:
raise PublicationBatchError(f"{label} KMS algorithm/key type is unsupported")
except (TypeError, ValueError, InvalidSignature) as exc:
raise PublicationBatchError(f"{label} KMS signature verification failed") from exc
return signature, signature_bytes
def _verify_online_kms_signature(
public_key: Any,
signature_block: Any,
*,
domain: bytes,
payload: Mapping[str, Any],
label: str,
) -> dict[str, Any]:
signature, _ = _verify_frozen_kms_signature(
public_key,
signature_block,
domain=domain,
payload=payload,
label=label,
include_request_id=True,
)
return signature
def _verify_kms_request_id_attestation(
public_key: Any,
attestation_value: Any,
*,
receipt_payload: Mapping[str, Any],
primary_signature: Mapping[str, Any],
attestation_domain: bytes,
label: str,
) -> dict[str, Any]:
attestation = _require_keys(
attestation_value,
f"{label} request_id attestation",
("schema_version", "payload", "signature"),
)
if attestation["schema_version"] != KMS_REQUEST_ID_ATTESTATION_SCHEMA_VERSION:
raise PublicationBatchError(f"{label} request_id attestation schema is unsupported")
try:
primary_signature_bytes = base64.b64decode(
_require_string(
primary_signature["value_base64"],
f"{label} primary signature value",
max_length=16384,
),
validate=True,
)
except (TypeError, ValueError) as exc:
raise PublicationBatchError(f"{label} primary signature encoding is invalid") from exc
expected_payload = {
"schema_version": KMS_REQUEST_ID_ATTESTATION_PAYLOAD_SCHEMA_VERSION,
"receipt_payload_sha256": _sha256_json(receipt_payload),
"primary_signature_sha256": _sha256_bytes(primary_signature_bytes),
"primary_provider": primary_signature["provider"],
"primary_key_reference": primary_signature["key_reference"],
"primary_key_version": primary_signature["key_version"],
"primary_algorithm": primary_signature["algorithm"],
"primary_request_id": primary_signature["request_id"],
}
payload = _require_keys(
attestation["payload"],
f"{label} request_id attestation payload",
tuple(expected_payload),
)
if payload != expected_payload:
raise PublicationBatchError(f"{label} request_id attestation binding drift")
_verify_frozen_kms_signature(
public_key,
attestation["signature"],
domain=attestation_domain,
payload=payload,
label=f"{label} request_id attestation",
include_request_id=False,
)
return attestation
def _read_pinned_raw_public_key(path: Path, *, expected_sha256: str, label: str) -> Ed25519PublicKey:
if not HEX64_RE.fullmatch(expected_sha256):
raise PublicationBatchError(f"{label} pin is not provisioned in the frozen source")
raw = secure_read_bytes(path, label, maximum_bytes=32)
if len(raw) != 32 or _sha256_bytes(raw) != expected_sha256:
raise PublicationBatchError(f"{label} does not match the frozen trust anchor")
try:
return Ed25519PublicKey.from_public_bytes(raw)
except ValueError as exc:
raise PublicationBatchError(f"{label} is not a valid Ed25519 public key") from exc
def _validate_approval_keyring(
keyring: Any,
*,
root_public_key: Ed25519PublicKey,
approved_at: datetime,
) -> list[dict[str, Any]]:
trusted = _require_keys(
keyring,
"approval keyring",
(
"schema_version", "root_key_id", "epoch", "issued_at", "expires_at",
"authorized_batch_manifest_raw_sha256", "keys",
"keyring_payload_sha256", "root_signature_base64",
),
)
if trusted["schema_version"] != APPROVAL_KEYRING_SCHEMA_VERSION:
raise PublicationBatchError("approval keyring schema is unsupported")
unsigned = {
field: trusted[field]
for field in (
"schema_version", "root_key_id", "epoch", "issued_at", "expires_at",
"authorized_batch_manifest_raw_sha256", "keys",
)
}
_require_sha(
trusted["authorized_batch_manifest_raw_sha256"],
"approval keyring authorized batch manifest raw SHA-256",
)
payload_sha256 = _require_sha(
trusted["keyring_payload_sha256"],
"approval keyring payload SHA-256",
)
if _sha256_json(unsigned) != payload_sha256:
raise PublicationBatchError("approval keyring payload hash drift")
if not HEX64_RE.fullmatch(TRUSTED_APPROVAL_ROOT_PUBLIC_KEY_SHA256):
raise PublicationBatchError("approval root public key pin is not provisioned")
if _sha256_bytes(_public_key_raw(root_public_key)) != TRUSTED_APPROVAL_ROOT_PUBLIC_KEY_SHA256:
raise PublicationBatchError("approval root public key does not match the frozen pin")
if trusted["root_key_id"] != TRUSTED_APPROVAL_ROOT_KEY_ID:
raise PublicationBatchError("approval keyring uses the wrong root key")
epoch = trusted["epoch"]
if (
not isinstance(epoch, int)
or isinstance(epoch, bool)
or epoch < 1
or not isinstance(FROZEN_APPROVAL_KEYRING_EPOCH, int)
or isinstance(FROZEN_APPROVAL_KEYRING_EPOCH, bool)
or FROZEN_APPROVAL_KEYRING_EPOCH < 1
):
raise PublicationBatchError("approval keyring epoch policy is not provisioned")
if epoch != FROZEN_APPROVAL_KEYRING_EPOCH:
raise PublicationBatchError("approval keyring epoch does not match the frozen candidate")
issued_at = _parse_time(trusted["issued_at"], "approval keyring issued_at")
expires_at = _parse_time(trusted["expires_at"], "approval keyring expires_at")
if expires_at <= issued_at or approved_at < issued_at or approved_at >= expires_at:
raise PublicationBatchError("approval keyring is not valid at approval time")
try:
signature = base64.b64decode(trusted["root_signature_base64"], validate=True)
root_public_key.verify(
signature,
APPROVAL_KEYRING_SIGNATURE_DOMAIN + _canonical(unsigned),
)
except (TypeError, ValueError, InvalidSignature) as exc:
raise PublicationBatchError("approval keyring root signature is invalid") from exc
keys = trusted["keys"]
if not isinstance(keys, list) or not keys:
raise PublicationBatchError("approval keyring keys are invalid")
root_raw = _public_key_raw(root_public_key)
validated: list[dict[str, Any]] = []
seen_ids: set[str] = set()
seen_public_keys: set[bytes] = set()
for value in keys:
key = _require_keys(
value,
"approval key",
(
"key_id", "algorithm", "public_key_pem", "approver_id", "name",
"not_before", "not_after", "revoked",
),
)
key_id = _require_string(key["key_id"], "approval key_id", max_length=128)
if key_id in seen_ids:
raise PublicationBatchError("approval keyring repeats a key_id")
seen_ids.add(key_id)
if key["algorithm"] != "Ed25519":
raise PublicationBatchError("approval key uses an unsupported algorithm")
if key["revoked"] is not False:
raise PublicationBatchError("revoked approval keys are forbidden")
key_reviewer = {
field: key[field]
for field in ("approver_id", "name")
}
if key_reviewer != SOLE_RELEASE_REVIEWER:
raise PublicationBatchError("approval key must belong to the configured sole release reviewer")
public_pem = _require_string(key["public_key_pem"], "approval public key", max_length=16384)
try:
public_key = serialization.load_pem_public_key(public_pem.encode("ascii"))
except (UnicodeError, ValueError) as exc:
raise PublicationBatchError("approval public key is invalid") from exc
if not isinstance(public_key, Ed25519PublicKey):
raise PublicationBatchError("approval public key must be Ed25519")
public_raw = _public_key_raw(public_key)
if public_raw == root_raw:
raise PublicationBatchError("approval key must differ from the offline root key")
if public_raw in seen_public_keys:
raise PublicationBatchError("approval keyring reuses an Ed25519 public key")
seen_public_keys.add(public_raw)
not_before = _parse_time(key["not_before"], "approval key not_before")
not_after = _parse_time(key["not_after"], "approval key not_after")
if not_after <= not_before:
raise PublicationBatchError("approval key validity window is invalid")
validated.append(
{
**key,
"public_key": public_key,
"public_key_raw": public_raw,
"not_before_parsed": not_before,
"not_after_parsed": not_after,
}
)
return validated
def validate_approval_receipt(
manifest: Mapping[str, Any],
manifest_raw_sha256: str,
receipt: Any,
keyring: Any,
root_public_key: Ed25519PublicKey,
) -> dict[str, Any]:
envelope = _require_keys(
receipt,
"approval receipt",
("schema_version", "approval_id", "payload", "signature"),
)
if envelope["schema_version"] != APPROVAL_SCHEMA_VERSION:
raise PublicationBatchError("approval receipt schema is unsupported")
payload = _require_keys(
envelope["payload"],
"approval payload",
(
"schema_version", "batch_manifest_raw_sha256", "batch_manifest_payload_sha256",
"decision", "approved_at", "expires_at", "key_id",
"approval_keyring_epoch", "approval_keyring_payload_sha256", "approver",
"asset_payload_sha256s",
"prompt_module_payload_sha256s", "golden_disposition_inventory_sha256",
"review_summary_sha256",
),
)
if payload["schema_version"] != APPROVAL_PAYLOAD_SCHEMA_VERSION or payload["decision"] != "approved":
raise PublicationBatchError("approval receipt is not an approved RC-06 batch receipt")
if payload["batch_manifest_payload_sha256"] != manifest["manifest_payload_sha256"]:
raise PublicationBatchError("approval receipt is not bound to this batch")
normalized_manifest_raw_sha256 = _require_sha(
manifest_raw_sha256,
"publication batch raw SHA-256",
)
if payload["batch_manifest_raw_sha256"] != normalized_manifest_raw_sha256:
raise PublicationBatchError("approval receipt is not bound to the exact manifest file")
approved_at = _parse_time(payload["approved_at"], "approval approved_at")
expires_at = _parse_time(payload["expires_at"], "approval expires_at")
if expires_at <= approved_at or expires_at - approved_at > MAX_APPROVAL_WINDOW:
raise PublicationBatchError("approval validity must be greater than zero and no longer than seven days")
approver = _require_sole_release_reviewer(payload["approver"], "approval approver")
expected_assets = {
item["template_id"]: item["asset_payload_sha256"]
for item in manifest["asset_batch"]["items"]
}
expected_modules = {
item["key"]: item["module_payload_sha256"]
for item in manifest["prompt_module_batch"]["items"]
}
if payload["asset_payload_sha256s"] != expected_assets:
raise PublicationBatchError("approval receipt asset identities drift")
if payload["prompt_module_payload_sha256s"] != expected_modules:
raise PublicationBatchError("approval receipt Prompt identities drift")
if payload["golden_disposition_inventory_sha256"] != manifest["golden_dispositions"]["inventory_sha256"]:
raise PublicationBatchError("approval receipt Golden disposition identity drift")
review_summary_sha256 = _require_sha(
payload["review_summary_sha256"],
"approval review summary SHA-256",
)
expected_review_summary_sha256 = _sha256_json(
build_approval_review_summary(
manifest,
manifest_raw_sha256=normalized_manifest_raw_sha256,
reviewer={
field: approver[field]
for field in RELEASE_REVIEWER_IDENTITY_FIELDS
},
)
)
if review_summary_sha256 != expected_review_summary_sha256:
raise PublicationBatchError("approval receipt does not match the exact review summary")
if not manifest["publication_control"]["golden_dispositions_complete"]:
raise PublicationBatchError("approval cannot release a batch with unresolved Golden dispositions")
_validate_disposition_approval_window(
manifest,
approved_at=approved_at,
expires_at=expires_at,
)
trusted_keys = _validate_approval_keyring(
keyring,
root_public_key=root_public_key,
approved_at=approved_at,
)
if payload["approval_keyring_epoch"] != keyring["epoch"]:
raise PublicationBatchError("approval receipt keyring epoch drift")
if _require_sha(
payload["approval_keyring_payload_sha256"],
"approval receipt keyring payload SHA-256",
) != keyring["keyring_payload_sha256"]:
raise PublicationBatchError("approval receipt keyring payload identity drift")
if keyring["authorized_batch_manifest_raw_sha256"] != normalized_manifest_raw_sha256:
raise PublicationBatchError("approval keyring does not authorize the exact batch manifest")
keyring_expires_at = _parse_time(keyring["expires_at"], "approval keyring expires_at")
if expires_at > keyring_expires_at:
raise PublicationBatchError("approval validity exceeds the trusted keyring window")
key_id = _require_string(payload["key_id"], "approval key_id", max_length=128)
matches = [
item
for item in trusted_keys
if item["key_id"] == key_id
]
if len(matches) != 1:
raise PublicationBatchError("approval key must resolve uniquely")
key = matches[0]
if approved_at < key["not_before_parsed"] or expires_at > key["not_after_parsed"]:
raise PublicationBatchError("approval validity is outside the trusted key window")
public_key = key["public_key"]
try:
signature = base64.b64decode(
_require_string(envelope["signature"], "approval signature", max_length=1024),
validate=True,
)
public_key.verify(signature, APPROVAL_SIGNATURE_DOMAIN + _canonical(payload))
except Exception as exc:
raise PublicationBatchError("approval signature verification failed") from exc
expected_id = f"rc06-batch-approval-{_sha256_bytes(_canonical(payload) + signature)[:24]}"
if envelope["approval_id"] != expected_id:
raise PublicationBatchError("approval_id does not match its signed material")
_assert_no_secret_material(envelope, "approval receipt")
return envelope
def _expected_apply_item_results(manifest: Mapping[str, Any]) -> list[dict[str, Any]]:
results = [
{
"kind": "asset",
"item_id": item["template_id"],
"expected_content_sha256": item["content_sha256"],
"online_content_sha256": item["content_sha256"],
"status": "applied_and_verified",
}
for item in manifest["asset_batch"]["items"]
] + [
{
"kind": "prompt_module",
"item_id": item["key"],
"expected_content_sha256": item["content_sha256"],
"online_content_sha256": item["content_sha256"],
"status": "applied_and_verified",
}
for item in manifest["prompt_module_batch"]["items"]
]
results.sort(key=lambda item: (item["kind"], item["item_id"]))
return results
def expected_runtime_snapshot_results(manifest: Mapping[str, Any]) -> list[dict[str, Any]]:
"""Project the fourteen executable Prompt identities into read-back evidence."""
dependencies = manifest["runtime_prompt_dependencies"]
if dependencies.get("publication_item_count") != 74 or dependencies.get("count") != 14:
raise PublicationBatchError(
"manifest must distinguish 74 publication items from 14 runtime snapshots"
)
results = [
{
"kind": item["kind"],
"runtime_key": item["runtime_key"],
"version": item["version"],
"expected_content_sha256": item["content_sha256"],
"online_content_sha256": item["content_sha256"],
"status": "published_and_resolved",
"publication_dependency": item["publication_dependency"],
"publication_module_dependencies": item["publication_module_dependencies"],
}
for item in dependencies["items"]
]
if len(results) != EXPECTED_RUNTIME_PROMPT_COUNT or len(
{item["runtime_key"] for item in results}
) != EXPECTED_RUNTIME_PROMPT_COUNT:
raise PublicationBatchError("runtime snapshot inventory must contain 14 identities")
return results
def publication_idempotency_key(
manifest_raw_sha256: str,
approval_raw_sha256: str,
legal_review_binding_sha256: str,
environment_id: str,
tenant_id: str,
) -> str:
identity = {
"operation": APPLY_OPERATION,
"manifest_raw_sha256": _require_sha(
manifest_raw_sha256, "publication manifest raw SHA-256"
),
"approval_raw_sha256": _require_sha(
approval_raw_sha256, "publication approval raw SHA-256"
),
"legal_review_binding_sha256": _require_sha(
legal_review_binding_sha256, "legal review binding SHA-256"
),
"environment_id": _require_string(
environment_id, "publication environment_id", max_length=256
),
"tenant_id": _require_string(tenant_id, "publication tenant_id", max_length=64),
}
return _sha256_json(identity)
def publication_transaction_id(idempotency_key: str) -> str:
"""Return a stable transaction identifier that fits the 64-character DB contract."""
normalized = _require_sha(idempotency_key, "publication idempotency key")
return "rc06-" + normalized[:59]
def validate_scene_legal_review_keyring(
keyring: Any,
keyring_raw_sha256: str,
*,
expected_sha256: str | None = None,
) -> dict[str, Any]:
"""Require the exact frozen canonical legal-review trust anchor.
The legal decision verifier checks the selected key's identity and validity.
This additional check prevents a caller from supplying an arbitrary self-signed
keyring to that verifier.
"""
trust_pin = (
TRUSTED_SCENE_LEGAL_REVIEW_KEYRING_SHA256
if expected_sha256 is None
else expected_sha256
)
if not HEX64_RE.fullmatch(trust_pin):
raise PublicationBatchError("scene legal review keyring trust is not provisioned")
normalized_raw_sha = _require_sha(
keyring_raw_sha256, "scene legal review keyring raw SHA-256"
)
if (
normalized_raw_sha != trust_pin
or _sha256_json(keyring) != trust_pin
):
raise PublicationBatchError(
"scene legal review keyring does not match the frozen canonical pin"
)
row = _require_keys(
keyring,
"scene legal review keyring",
("schema_version", "keys"),
)
if row["schema_version"] != "yuqei.scene-source-legal-review-keyring.v1":
raise PublicationBatchError("scene legal review keyring schema is unsupported")
keys = row["keys"]
if not isinstance(keys, list) or not keys:
raise PublicationBatchError("scene legal review keyring must contain trusted keys")
seen: set[str] = set()
for index, value in enumerate(keys):
key = _require_keys(
value,
f"scene legal review key {index}",
(
"key_id",
"status",
"revoked_at",
"valid_from",
"valid_until",
"reviewer_name",
"reviewer_organization",
"reviewer_qualification",
"credential_reference",
"public_key_raw_base64",
),
)
key_id = _require_string(key["key_id"], "scene legal review key_id", max_length=128)
if key_id in seen:
raise PublicationBatchError("scene legal review keyring contains duplicate key ids")
seen.add(key_id)
if key["status"] != "trusted" or key["revoked_at"] is not None:
raise PublicationBatchError("scene legal review keyring contains an inactive key")
valid_from = _parse_time(key["valid_from"], "scene legal review key valid_from")
valid_until = _parse_time(key["valid_until"], "scene legal review key valid_until")
if valid_until <= valid_from:
raise PublicationBatchError("scene legal review key validity window is invalid")
for field in (
"reviewer_name",
"reviewer_organization",
"reviewer_qualification",
"credential_reference",
):
_require_string(key[field], f"scene legal review key {field}", max_length=512)
try:
public_raw = base64.b64decode(
_require_string(
key["public_key_raw_base64"],
"scene legal review public key",
max_length=128,
),
validate=True,
)
Ed25519PublicKey.from_public_bytes(public_raw)
except (TypeError, ValueError) as exc:
raise PublicationBatchError("scene legal review public key is invalid") from exc
return row
def _load_scene_legal_review_module() -> Any:
path = Path(__file__).resolve().with_name("build-scene-source-legal-review.py")
if not path.is_file():
raise PublicationBatchError("scene legal review validator is absent")
spec = importlib.util.spec_from_file_location("rc06_scene_source_legal_review", path)
if spec is None or spec.loader is None:
raise PublicationBatchError("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_evidence(
repo: Path,
manifest: Mapping[str, Any],
approval: Mapping[str, Any],
request: Any,
decision: Any,
keyring: Any,
keyring_raw_sha256: str,
*,
now: datetime,
validator: Any | None = None,
) -> tuple[dict[str, Any], str]:
"""Validate the qualified-human 30-scene/43-occurrence proof and trust pin."""
if not isinstance(request, dict) or not isinstance(decision, dict):
raise PublicationBatchError("scene legal review request and decision are required")
validate_scene_legal_review_keyring(keyring, keyring_raw_sha256)
if request.get("candidate_commit") != manifest["candidate"]["commit"]:
raise PublicationBatchError("scene legal review candidate does not match the batch")
scope = request.get("scope")
if not isinstance(scope, dict) or scope.get("scene_count") != 30 or scope.get(
"reference_occurrence_count"
) != 43:
raise PublicationBatchError("scene legal review must cover 30 scenes and 43 references")
request_sha256 = request.get("request_sha256")
if not isinstance(request_sha256, str) or not HEX64_RE.fullmatch(request_sha256):
raise PublicationBatchError("scene legal review request_sha256 is invalid")
if decision.get("request_sha256") != request_sha256:
raise PublicationBatchError("scene legal review decision is not bound to its request")
verifier = validator or _load_scene_legal_review_module()
try:
verified_request = verifier.verify_request(request, repo)
summary = verifier.verify_signed_decision(
verified_request,
decision,
keyring,
checked_at=now.astimezone(UTC).isoformat(timespec="seconds"),
)
except Exception as exc:
raise PublicationBatchError(f"scene legal review validation failed: {exc}") from exc
if (
summary.get("status") != "verified_qualified_human_review"
or summary.get("request_sha256") != request_sha256
or summary.get("reviewed_occurrence_count") != 43
or summary.get("all_current_effectiveness_verified") is not True
or summary.get("all_transaction_applicability_verified") is not True
or summary.get("authorizes_publication_by_itself") is not False
):
raise PublicationBatchError("scene legal review verification summary is incomplete")
approval_expires_at = _parse_time(approval["payload"]["expires_at"], "approval expires_at")
legal_expires_at = _parse_time(summary.get("expires_at"), "legal review expires_at")
if legal_expires_at > approval_expires_at:
raise PublicationBatchError("scene legal review validity exceeds the approval window")
binding = {
"request_sha256": request_sha256,
"decision_sha256": _sha256_json(decision),
"keyring_raw_sha256": keyring_raw_sha256,
}
return summary, _sha256_json(binding)
def validate_scene_legal_review_evidence_online(
manifest: Mapping[str, Any],
approval: Mapping[str, Any],
request: Any,
decision: Any,
keyring: Any,
keyring_raw_sha256: str,
*,
now: datetime,
validator: Any | None = None,
) -> tuple[dict[str, Any], str]:
"""Verify frozen legal evidence without Git/worktree access.
The offline authority must still call ``validate_scene_legal_review_evidence``
so the request is rebuilt from the immutable Git candidate. This narrower
verifier is for the production facade, whose image has no ``.git``: it
verifies the request's embedded hash/30-by-43 structure, the frozen keyring,
and the qualified-reviewer signature and validity window.
"""
validate_scene_legal_review_keyring(keyring, keyring_raw_sha256)
row = _require_keys(
request,
"scene legal review request",
(
"schema_version",
"status",
"candidate_commit",
"created_at",
"scope",
"source_files",
"occurrences",
"guardrails",
"request_sha256",
),
)
request_sha256 = _require_sha(
row["request_sha256"], "scene legal review request_sha256"
)
if _sha256_json({key: value for key, value in row.items() if key != "request_sha256"}) != request_sha256:
raise PublicationBatchError("scene legal review request embedded hash drift")
if (
row["schema_version"] != "yuqei.scene-source-legal-review-request.v1"
or row["status"] != "pending_qualified_human_review"
or row["candidate_commit"] != manifest["candidate"]["commit"]
):
raise PublicationBatchError("scene legal review request identity drift")
_parse_time(row["created_at"], "scene legal review request created_at")
scope = _require_keys(
row["scope"],
"scene legal review scope",
(
"scene_count",
"reference_occurrence_count",
"distinct_source_record_count",
"distinct_url_count",
),
)
if scope["scene_count"] != 30 or scope["reference_occurrence_count"] != 43:
raise PublicationBatchError("scene legal review must cover 30 scenes and 43 references")
occurrences = row["occurrences"]
if not isinstance(occurrences, list) or len(occurrences) != 43:
raise PublicationBatchError("scene legal review occurrence inventory is incomplete")
occurrence_ids: list[str] = []
for index, occurrence in enumerate(occurrences):
if not isinstance(occurrence, dict):
raise PublicationBatchError(f"scene legal review occurrence {index} is invalid")
occurrence_id = _require_string(
occurrence.get("occurrence_id"),
f"scene legal review occurrence {index} id",
max_length=512,
)
_require_sha(
occurrence.get("source_record_sha256"),
f"scene legal review occurrence {index} source record SHA-256",
)
occurrence_ids.append(occurrence_id)
if occurrence_ids != sorted(occurrence_ids) or len(set(occurrence_ids)) != 43:
raise PublicationBatchError("scene legal review occurrence identities drift")
if row["guardrails"] != {
"not_legal_approval": True,
"authorizes_publication": False,
"ai_must_not_supply_human_decisions": True,
"all_occurrences_require_qualified_human_review": True,
}:
raise PublicationBatchError("scene legal review guardrails drift")
if not isinstance(row["source_files"], list) or not row["source_files"]:
raise PublicationBatchError("scene legal review source file inventory is empty")
verifier = validator or _load_scene_legal_review_module()
try:
summary = verifier.verify_signed_decision(
row,
decision,
keyring,
checked_at=now.astimezone(UTC).isoformat(timespec="seconds"),
)
except Exception as exc:
raise PublicationBatchError(f"scene legal review validation failed: {exc}") from exc
if (
summary.get("status") != "verified_qualified_human_review"
or summary.get("request_sha256") != request_sha256
or summary.get("reviewed_occurrence_count") != 43
or summary.get("all_current_effectiveness_verified") is not True
or summary.get("all_transaction_applicability_verified") is not True
or summary.get("authorizes_publication_by_itself") is not False
):
raise PublicationBatchError("scene legal review verification summary is incomplete")
legal_expires_at = _parse_time(summary.get("expires_at"), "legal review expires_at")
if legal_expires_at > _parse_time(
approval["payload"]["expires_at"], "approval expires_at"
):
raise PublicationBatchError("scene legal review validity exceeds the approval window")
binding = {
"request_sha256": request_sha256,
"decision_sha256": _sha256_json(decision),
"keyring_raw_sha256": keyring_raw_sha256,
}
return summary, _sha256_json(binding)
def validate_apply_challenge(
manifest: Mapping[str, Any],
manifest_raw_sha256: str,
approval_raw_sha256: str,
apply_service_public_key: Ed25519PublicKey,
challenge: Any,
*,
legal_review_binding_sha256: str,
legal_review_expires_at: str,
environment_id: str,
tenant_id: str,
) -> dict[str, Any]:
if not HEX64_RE.fullmatch(TRUSTED_APPLY_SERVICE_PUBLIC_KEY_SHA256):
raise PublicationBatchError("apply service public key pin is not provisioned")
apply_public_raw = _public_key_raw(apply_service_public_key)
if _sha256_bytes(apply_public_raw) != TRUSTED_APPLY_SERVICE_PUBLIC_KEY_SHA256:
raise PublicationBatchError("apply challenge key does not match the frozen pin")
envelope = _require_keys(
challenge,
"apply challenge",
("schema_version", "challenge_id", "payload", "signature"),
)
if envelope["schema_version"] != APPLY_CHALLENGE_SCHEMA_VERSION:
raise PublicationBatchError("apply challenge schema is unsupported")
payload = _require_keys(
envelope["payload"],
"apply challenge payload",
(
"schema_version",
"nonce_base64",
"candidate_commit",
"candidate_tag",
"batch_manifest_raw_sha256",
"batch_manifest_payload_sha256",
"approval_receipt_sha256",
"legal_source_review_binding_sha256",
"legal_source_review_expires_at",
"operation",
"environment_id",
"tenant_id",
"idempotency_key",
"transaction_id",
"actor",
"issued_at",
"expires_at",
),
)
if (
payload["schema_version"] != APPLY_CHALLENGE_PAYLOAD_SCHEMA_VERSION
or payload["candidate_commit"] != manifest["candidate"]["commit"]
or payload["candidate_tag"] != manifest["candidate"]["tag"]
or payload["batch_manifest_payload_sha256"]
!= manifest["manifest_payload_sha256"]
or payload["approval_receipt_sha256"]
!= _require_sha(approval_raw_sha256, "approval raw SHA-256")
or payload["legal_source_review_binding_sha256"]
!= _require_sha(
legal_review_binding_sha256,
"expected legal review binding SHA-256",
)
or payload["legal_source_review_expires_at"] != legal_review_expires_at
or payload["operation"] != APPLY_OPERATION
):
raise PublicationBatchError("apply challenge candidate or operation binding drift")
if payload["batch_manifest_raw_sha256"] != _require_sha(
manifest_raw_sha256, "apply challenge manifest raw SHA-256"
):
raise PublicationBatchError("apply challenge manifest raw binding drift")
normalized_environment_id = _require_string(
payload["environment_id"], "apply challenge environment_id", max_length=256
)
normalized_expected_environment = _require_string(
environment_id, "expected apply challenge environment_id", max_length=256
)
normalized_tenant_id = _require_string(
payload["tenant_id"], "apply challenge tenant_id", max_length=64
)
normalized_expected_tenant = _require_string(
tenant_id, "expected apply challenge tenant_id", max_length=64
)
if (
normalized_environment_id != payload["environment_id"]
or normalized_environment_id != normalized_expected_environment
or normalized_tenant_id != payload["tenant_id"]
or normalized_tenant_id != normalized_expected_tenant
):
raise PublicationBatchError("apply challenge environment_id must be canonical")
expected_idempotency_key = publication_idempotency_key(
manifest_raw_sha256,
approval_raw_sha256,
legal_review_binding_sha256,
normalized_environment_id,
normalized_tenant_id,
)
if payload["idempotency_key"] != expected_idempotency_key:
raise PublicationBatchError("apply challenge idempotency binding drift")
if payload["transaction_id"] != publication_transaction_id(expected_idempotency_key):
raise PublicationBatchError("apply challenge transaction binding drift")
actor = _require_keys(payload["actor"], "apply challenge actor", ("type", "component"))
if actor != {
"type": "system",
"component": TRUSTED_ONLINE_APPLY_SERVICE_COMPONENT,
}:
raise PublicationBatchError("apply challenge actor is not the trusted online service")
issued_at = _parse_time(payload["issued_at"], "apply challenge issued_at")
expires_at = _parse_time(payload["expires_at"], "apply challenge expires_at")
legal_expires_at = _parse_time(
payload["legal_source_review_expires_at"],
"apply challenge legal review expires_at",
)
if (
expires_at <= issued_at
or expires_at - issued_at > MAX_APPLY_CHALLENGE_TTL
or expires_at > legal_expires_at
):
raise PublicationBatchError("apply challenge TTL is invalid")
try:
nonce = base64.b64decode(
_require_string(
payload["nonce_base64"], "apply challenge nonce", max_length=128
),
validate=True,
)
signature = base64.b64decode(
_require_string(
envelope["signature"], "apply challenge signature", max_length=1024
),
validate=True,
)
if len(nonce) != 32:
raise ValueError("challenge nonce must contain 32 bytes")
apply_service_public_key.verify(
signature,
APPLY_CHALLENGE_SIGNATURE_DOMAIN + _canonical(payload),
)
except (TypeError, ValueError, InvalidSignature) as exc:
raise PublicationBatchError("apply challenge signature verification failed") from exc
expected_id = (
"rc06-apply-challenge-"
+ _sha256_bytes(_canonical(payload) + signature)[:24]
)
if envelope["challenge_id"] != expected_id:
raise PublicationBatchError("apply challenge_id does not match its signed material")
_assert_no_secret_material(envelope, "apply challenge")
return envelope
def validate_online_transaction_receipt(
manifest: Mapping[str, Any],
manifest_raw_sha256: str,
approval_raw_sha256: str,
approval: Mapping[str, Any],
apply_service_public_key: Ed25519PublicKey,
online_service_public_key: Any,
receipt: Any,
*,
legal_review_binding_sha256: str,
legal_review_expires_at: str,
environment_id: str,
tenant_id: str,
) -> dict[str, Any]:
"""Verify server-originated database transaction evidence.
The public-key hash and environment allowlist are frozen source values.
The caller therefore cannot turn a locally fabricated payload into online
evidence merely by supplying another key or environment identifier.
"""
if (
not TRUSTED_ONLINE_APPLY_ENVIRONMENT_IDS
or len(set(TRUSTED_ONLINE_APPLY_ENVIRONMENT_IDS))
!= len(TRUSTED_ONLINE_APPLY_ENVIRONMENT_IDS)
or any(
not isinstance(value, str) or not value.strip() or value != value.strip()
for value in TRUSTED_ONLINE_APPLY_ENVIRONMENT_IDS
)
):
raise PublicationBatchError(
"online publication environment allowlist is not provisioned"
)
if not HEX64_RE.fullmatch(TRUSTED_ONLINE_APPLY_SERVICE_PUBLIC_KEY_SPKI_SHA256):
raise PublicationBatchError(
"online publication service SPKI pin is not provisioned"
)
online_public_spki = _public_key_spki(online_service_public_key)
if (
_sha256_bytes(online_public_spki)
!= TRUSTED_ONLINE_APPLY_SERVICE_PUBLIC_KEY_SPKI_SHA256
):
raise PublicationBatchError(
"online publication service public key does not match the frozen SPKI pin"
)
envelope = _require_keys(
receipt,
"online transaction receipt",
(
"schema_version",
"receipt_id",
"payload",
"signature",
"request_id_attestation",
),
)
if envelope["schema_version"] != ONLINE_TRANSACTION_RECEIPT_SCHEMA_VERSION:
raise PublicationBatchError("online transaction receipt schema is unsupported")
payload = _require_keys(
envelope["payload"],
"online transaction receipt payload",
(
"schema_version",
"candidate_commit",
"candidate_tag",
"batch_manifest_raw_sha256",
"batch_manifest_payload_sha256",
"approval_receipt_sha256",
"legal_source_review_binding_sha256",
"environment_id",
"tenant_id",
"idempotency_key",
"transaction_id",
"transaction_mode",
"cross_database_atomicity",
"coordinator_deployment",
"participant_evidence",
"committed_at",
"authority_challenge",
"generated_by",
"item_results",
"write_count",
"status",
),
)
if (
payload["schema_version"] != ONLINE_TRANSACTION_PAYLOAD_SCHEMA_VERSION
or payload["candidate_commit"] != manifest["candidate"]["commit"]
or payload["candidate_tag"] != manifest["candidate"]["tag"]
or payload["status"] != "committed_and_verified"
or payload["transaction_mode"] != TRANSACTION_MODE
or payload["cross_database_atomicity"] is not False
):
raise PublicationBatchError("online transaction receipt identity is invalid")
if payload["batch_manifest_raw_sha256"] != _require_sha(
manifest_raw_sha256, "online transaction manifest raw SHA-256"
):
raise PublicationBatchError("online transaction raw manifest binding drift")
if payload["batch_manifest_payload_sha256"] != manifest["manifest_payload_sha256"]:
raise PublicationBatchError("online transaction receipt is not bound to this batch")
if payload["approval_receipt_sha256"] != _require_sha(
approval_raw_sha256, "approval raw SHA-256"
):
raise PublicationBatchError(
"online transaction receipt is not bound to the approval receipt"
)
if payload["legal_source_review_binding_sha256"] != _require_sha(
legal_review_binding_sha256, "expected legal review binding SHA-256"
):
raise PublicationBatchError(
"online transaction receipt is not bound to the legal review"
)
normalized_environment_id = _require_string(
payload["environment_id"], "online transaction environment_id", max_length=256
)
normalized_expected_environment = _require_string(
environment_id, "expected online transaction environment_id", max_length=256
)
normalized_tenant_id = _require_string(
payload["tenant_id"], "online transaction tenant_id", max_length=64
)
normalized_expected_tenant = _require_string(
tenant_id, "expected online transaction tenant_id", max_length=64
)
if (
normalized_environment_id != payload["environment_id"]
or normalized_environment_id != normalized_expected_environment
or normalized_tenant_id != payload["tenant_id"]
or normalized_tenant_id != normalized_expected_tenant
):
raise PublicationBatchError(
"online transaction environment or tenant binding drift"
)
if normalized_environment_id not in TRUSTED_ONLINE_APPLY_ENVIRONMENT_IDS:
raise PublicationBatchError(
"online transaction environment is not in the frozen allowlist"
)
expected_idempotency_key = publication_idempotency_key(
manifest_raw_sha256,
approval_raw_sha256,
legal_review_binding_sha256,
normalized_environment_id,
normalized_tenant_id,
)
if payload["idempotency_key"] != expected_idempotency_key:
raise PublicationBatchError("online transaction idempotency binding drift")
normalized_transaction_id = _require_string(
payload["transaction_id"], "online transaction_id", max_length=256
)
if (
normalized_transaction_id != payload["transaction_id"]
or normalized_transaction_id
!= publication_transaction_id(expected_idempotency_key)
):
raise PublicationBatchError("online transaction identifier binding drift")
committed_at = _parse_time(payload["committed_at"], "online committed_at")
approval_payload = approval["payload"]
if committed_at < _parse_time(
approval_payload["approved_at"], "approval approved_at"
) or committed_at >= _parse_time(
approval_payload["expires_at"], "approval expires_at"
):
raise PublicationBatchError(
"online transaction receipt was generated outside the approval window"
)
challenge = validate_apply_challenge(
manifest,
manifest_raw_sha256,
approval_raw_sha256,
apply_service_public_key,
payload["authority_challenge"],
legal_review_binding_sha256=legal_review_binding_sha256,
legal_review_expires_at=legal_review_expires_at,
environment_id=normalized_environment_id,
tenant_id=normalized_tenant_id,
)
challenge_payload = challenge["payload"]
challenge_issued_at = _parse_time(
challenge_payload["issued_at"], "apply challenge issued_at"
)
challenge_expires_at = _parse_time(
challenge_payload["expires_at"], "apply challenge expires_at"
)
approval_approved_at = _parse_time(
approval_payload["approved_at"], "approval approved_at"
)
approval_expires_at = _parse_time(
approval_payload["expires_at"], "approval expires_at"
)
if (
challenge_payload["environment_id"] != normalized_environment_id
or challenge_payload["tenant_id"] != normalized_tenant_id
or challenge_payload["idempotency_key"] != expected_idempotency_key
or challenge_payload["transaction_id"] != normalized_transaction_id
or challenge_issued_at < approval_approved_at
or challenge_expires_at > approval_expires_at
or committed_at < challenge_issued_at
or committed_at >= challenge_expires_at
):
raise PublicationBatchError(
"online transaction receipt does not satisfy its apply challenge"
)
actor = _require_keys(
payload["generated_by"], "online transaction generator", ("type", "component")
)
if actor != {
"type": "system",
"component": TRUSTED_ONLINE_APPLY_SERVICE_COMPONENT,
}:
raise PublicationBatchError(
"online transaction receipt was not generated by the trusted service"
)
expected_item_results = _expected_apply_item_results(manifest)
if payload["item_results"] != expected_item_results:
raise PublicationBatchError("online transaction 74-item evidence drift")
if payload["write_count"] != EXPECTED_ASSET_COUNT + EXPECTED_MODULE_COUNT:
raise PublicationBatchError("online transaction write count must be exactly 74")
image_digests = {
item["role"]: item["manifest_digest"]
for item in manifest["candidate"]["images"]
}
coordinator_deployment = _require_keys(
payload["coordinator_deployment"],
"online transaction coordinator deployment",
("component", "candidate_commit", "release_image_digest"),
)
if coordinator_deployment != {
"component": TRUSTED_ONLINE_APPLY_SERVICE_COMPONENT,
"candidate_commit": manifest["candidate"]["commit"],
"release_image_digest": image_digests["contract-api"],
}:
raise PublicationBatchError("online transaction coordinator deployment drift")
participant_evidence = payload["participant_evidence"]
if not isinstance(participant_evidence, list) or len(participant_evidence) != 2:
raise PublicationBatchError(
"online transaction must contain exactly two participant commit proofs"
)
expected_participants = {
"ai-platform": (
EXPECTED_MODULE_COUNT,
EXPECTED_RUNTIME_PROMPT_COUNT,
image_digests["ai-platform-api"],
_sha256_json(
[item for item in expected_item_results if item["kind"] == "prompt_module"]
),
),
"contract-platform": (
EXPECTED_ASSET_COUNT,
0,
image_digests["contract-api"],
_sha256_json([item for item in expected_item_results if item["kind"] == "asset"]),
),
}
if [item.get("participant") for item in participant_evidence] != sorted(
expected_participants
):
raise PublicationBatchError("online participant evidence ordering or identity drift")
for index, value in enumerate(participant_evidence):
participant = _require_keys(
value,
f"online participant evidence {index}",
(
"participant",
"state",
"transaction_id",
"candidate_commit",
"release_image_digest",
"committed_at",
"write_count",
"runtime_snapshot_count",
"committed_item_results_sha256",
"durable_commit_evidence_sha256",
),
)
(
expected_write_count,
expected_runtime_count,
expected_image_digest,
expected_results_sha,
) = expected_participants[
participant["participant"]
]
participant_committed_at = _parse_time(
participant["committed_at"],
f"online participant {participant['participant']} committed_at",
)
if (
participant["state"] != "committed"
or participant["transaction_id"] != normalized_transaction_id
or participant["candidate_commit"] != manifest["candidate"]["commit"]
or participant["release_image_digest"] != expected_image_digest
or participant_committed_at < challenge_issued_at
or participant_committed_at > committed_at
or participant_committed_at >= challenge_expires_at
or participant_committed_at >= approval_expires_at
or participant["write_count"] != expected_write_count
or participant["runtime_snapshot_count"] != expected_runtime_count
or participant["committed_item_results_sha256"] != expected_results_sha
):
raise PublicationBatchError("online participant commit evidence drift")
supplied_durable_sha = _require_sha(
participant["durable_commit_evidence_sha256"],
"online participant durable commit evidence SHA-256",
)
durable_projection = {
key: child
for key, child in participant.items()
if key != "durable_commit_evidence_sha256"
}
if supplied_durable_sha != _sha256_json(durable_projection):
raise PublicationBatchError(
"online participant durable commit evidence hash drift"
)
signature = _verify_online_kms_signature(
online_service_public_key,
envelope["signature"],
domain=ONLINE_TRANSACTION_SIGNATURE_DOMAIN,
payload=payload,
label="online transaction receipt",
)
request_id_attestation = _verify_kms_request_id_attestation(
online_service_public_key,
envelope["request_id_attestation"],
receipt_payload=payload,
primary_signature=signature,
attestation_domain=ONLINE_REQUEST_ID_ATTESTATION_DOMAIN,
label="online transaction receipt",
)
expected_id = (
"rc06-online-transaction-"
+ _sha256_bytes(
_canonical(payload)
+ _canonical(signature)
+ _canonical(request_id_attestation)
)[:24]
)
if envelope["receipt_id"] != expected_id:
raise PublicationBatchError(
"online transaction receipt_id does not match its signed material"
)
_assert_no_secret_material(envelope, "online transaction receipt")
return envelope
def validate_runtime_snapshot_receipt(
manifest: Mapping[str, Any],
manifest_raw_sha256: str,
approval_raw_sha256: str,
approval: Mapping[str, Any],
apply_service_public_key: Ed25519PublicKey,
online_service_public_key: Any,
online_transaction_receipt: Any,
receipt: Any,
*,
legal_review_binding_sha256: str,
legal_review_expires_at: str,
environment_id: str,
tenant_id: str,
) -> dict[str, Any]:
"""Verify read-back proof bound to the exact committed online receipt."""
online_receipt = 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,
)
envelope = _require_keys(
receipt,
"runtime snapshot receipt",
(
"schema_version",
"receipt_id",
"payload",
"signature",
"request_id_attestation",
),
)
if envelope["schema_version"] != RUNTIME_RECEIPT_SCHEMA_VERSION:
raise PublicationBatchError("runtime snapshot receipt schema is unsupported")
payload = _require_keys(
envelope["payload"],
"runtime snapshot receipt payload",
(
"schema_version",
"batch_manifest_raw_sha256",
"batch_manifest_payload_sha256",
"approval_receipt_sha256",
"legal_source_review_binding_sha256",
"environment_id",
"tenant_id",
"idempotency_key",
"transaction_id",
"online_transaction_receipt_sha256",
"captured_at",
"generated_by",
"transaction_mode",
"cross_database_atomicity",
"publication_item_count",
"runtime_snapshot_dependencies",
"runtime_snapshot_dependency_count",
"status",
),
)
online_payload = online_receipt["payload"]
expected_online_sha = _sha256_json(online_receipt)
if (
payload["schema_version"] != RUNTIME_PAYLOAD_SCHEMA_VERSION
or payload["batch_manifest_raw_sha256"] != manifest_raw_sha256
or payload["batch_manifest_payload_sha256"]
!= manifest["manifest_payload_sha256"]
or payload["approval_receipt_sha256"] != approval_raw_sha256
or payload["legal_source_review_binding_sha256"]
!= legal_review_binding_sha256
or payload["environment_id"] != environment_id
or payload["tenant_id"] != tenant_id
or payload["idempotency_key"] != online_payload["idempotency_key"]
or payload["transaction_id"] != online_payload["transaction_id"]
or payload["online_transaction_receipt_sha256"] != expected_online_sha
or payload["transaction_mode"] != TRANSACTION_MODE
or payload["cross_database_atomicity"] is not False
or payload["publication_item_count"]
!= EXPECTED_ASSET_COUNT + EXPECTED_MODULE_COUNT
or payload["runtime_snapshot_dependency_count"]
!= EXPECTED_RUNTIME_PROMPT_COUNT
or payload["status"] != "published_and_resolved"
):
raise PublicationBatchError("runtime snapshot receipt binding drift")
if payload["runtime_snapshot_dependencies"] != expected_runtime_snapshot_results(
manifest
):
raise PublicationBatchError("runtime snapshot 14-item evidence drift")
captured_at = _parse_time(payload["captured_at"], "runtime captured_at")
committed_at = _parse_time(online_payload["committed_at"], "online committed_at")
approval_expires_at = _parse_time(
approval["payload"]["expires_at"], "approval expires_at"
)
challenge_expires_at = _parse_time(
online_payload["authority_challenge"]["payload"]["expires_at"],
"apply challenge expires_at",
)
if (
captured_at < committed_at
or captured_at >= approval_expires_at
or captured_at >= challenge_expires_at
):
raise PublicationBatchError("runtime snapshot receipt is outside its authority window")
actor = _require_keys(
payload["generated_by"],
"runtime snapshot generator",
("type", "component"),
)
if actor != {
"type": "system",
"component": TRUSTED_ONLINE_APPLY_SERVICE_COMPONENT,
}:
raise PublicationBatchError("runtime snapshot receipt generator is untrusted")
signature = _verify_online_kms_signature(
online_service_public_key,
envelope["signature"],
domain=RUNTIME_SIGNATURE_DOMAIN,
payload=payload,
label="runtime snapshot receipt",
)
request_id_attestation = _verify_kms_request_id_attestation(
online_service_public_key,
envelope["request_id_attestation"],
receipt_payload=payload,
primary_signature=signature,
attestation_domain=RUNTIME_REQUEST_ID_ATTESTATION_DOMAIN,
label="runtime snapshot receipt",
)
expected_id = (
"rc06-runtime-snapshot-"
+ _sha256_bytes(
_canonical(payload)
+ _canonical(signature)
+ _canonical(request_id_attestation)
)[:24]
)
if envelope["receipt_id"] != expected_id:
raise PublicationBatchError(
"runtime snapshot receipt_id does not match its signed material"
)
_assert_no_secret_material(envelope, "runtime snapshot receipt")
return envelope
def validate_apply_receipt(
manifest: Mapping[str, Any],
manifest_raw_sha256: str,
approval: Mapping[str, Any],
approval_keyring: Mapping[str, Any],
approval_root_public_key: Ed25519PublicKey,
apply_service_public_key: Ed25519PublicKey,
online_service_public_key: Any,
approval_raw_sha256: str,
receipt: Any,
*,
legal_review_binding_sha256: str,
legal_review_expires_at: str,
environment_id: str,
tenant_id: str,
) -> dict[str, Any]:
validate_approval_receipt(
manifest,
manifest_raw_sha256,
approval,
approval_keyring,
approval_root_public_key,
)
envelope = _require_keys(
receipt,
"apply receipt",
("schema_version", "receipt_id", "payload", "signature"),
)
if envelope["schema_version"] != APPLY_SCHEMA_VERSION:
raise PublicationBatchError("apply receipt schema is unsupported")
row = _require_keys(
envelope["payload"],
"apply receipt payload",
(
"schema_version",
"batch_manifest_raw_sha256",
"batch_manifest_payload_sha256",
"approval_receipt_sha256",
"legal_source_review_binding_sha256",
"environment_id",
"tenant_id",
"idempotency_key",
"transaction_id",
"authorized_commit_at",
"countersigned_at",
"generated_by",
"transaction_mode",
"cross_database_atomicity",
"item_results",
"write_count",
"status",
"online_transaction_receipt",
"runtime_snapshot_receipt",
),
)
if (
row["schema_version"] != APPLY_PAYLOAD_SCHEMA_VERSION
or row["status"] != "applied_and_verified"
or row["transaction_mode"] != TRANSACTION_MODE
or row["cross_database_atomicity"] is not False
):
raise PublicationBatchError("apply receipt is not a successful RC-06 receipt")
if row["batch_manifest_raw_sha256"] != _require_sha(
manifest_raw_sha256, "apply manifest raw SHA-256"
):
raise PublicationBatchError("apply receipt raw manifest binding drift")
if row["batch_manifest_payload_sha256"] != manifest["manifest_payload_sha256"]:
raise PublicationBatchError("apply receipt is not bound to this batch")
if row["approval_receipt_sha256"] != _require_sha(approval_raw_sha256, "approval raw SHA-256"):
raise PublicationBatchError("apply receipt is not bound to the approval receipt")
if row["legal_source_review_binding_sha256"] != _require_sha(
legal_review_binding_sha256, "expected legal review binding SHA-256"
):
raise PublicationBatchError("apply receipt is not bound to the legal review")
if (
row["environment_id"]
!= _require_string(environment_id, "expected apply environment_id", max_length=256)
or row["tenant_id"]
!= _require_string(tenant_id, "expected apply tenant_id", max_length=64)
):
raise PublicationBatchError("apply receipt environment or tenant binding drift")
expected_idempotency_key = publication_idempotency_key(
manifest_raw_sha256,
approval_raw_sha256,
legal_review_binding_sha256,
environment_id,
tenant_id,
)
if (
row["idempotency_key"] != expected_idempotency_key
or row["transaction_id"] != publication_transaction_id(expected_idempotency_key)
):
raise PublicationBatchError("apply receipt transaction identity drift")
authorized_commit_at = _parse_time(
row["authorized_commit_at"], "apply authorized_commit_at"
)
countersigned_at = _parse_time(
row["countersigned_at"], "apply countersigned_at"
)
approval_payload = approval["payload"]
approval_expires_at = _parse_time(
approval_payload["expires_at"], "approval expires_at"
)
legal_expires_at = _parse_time(
legal_review_expires_at, "legal review expires_at"
)
actor = _require_keys(row["generated_by"], "apply generator", ("type", "component"))
if actor != {"type": "system", "component": "rc06-apply-authority"}:
raise PublicationBatchError("per-item apply evidence must be authority generated")
expected_results = _expected_apply_item_results(manifest)
if row["item_results"] != expected_results:
raise PublicationBatchError("apply receipt 74-item online evidence drift")
if row["write_count"] != EXPECTED_ASSET_COUNT + EXPECTED_MODULE_COUNT:
raise PublicationBatchError("apply receipt write count must be exactly 74")
if approval_payload["batch_manifest_payload_sha256"] != manifest["manifest_payload_sha256"]:
raise PublicationBatchError("approval/apply batch identity mismatch")
online_receipt = 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,
)
runtime_receipt = 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,
)
online_payload = online_receipt["payload"]
runtime_payload = runtime_receipt["payload"]
if (
row["environment_id"] != online_payload["environment_id"]
or row["tenant_id"] != online_payload["tenant_id"]
or row["legal_source_review_binding_sha256"]
!= online_payload["legal_source_review_binding_sha256"]
or row["idempotency_key"] != online_payload["idempotency_key"]
or row["transaction_id"] != online_payload["transaction_id"]
or row["item_results"] != online_payload["item_results"]
or row["write_count"] != online_payload["write_count"]
or runtime_payload["online_transaction_receipt_sha256"]
!= _sha256_json(online_receipt)
):
raise PublicationBatchError(
"apply receipt does not exactly bind the online/runtime evidence pair"
)
runtime_captured_at = _parse_time(
runtime_payload["captured_at"], "runtime captured_at"
)
if authorized_commit_at != runtime_captured_at:
raise PublicationBatchError(
"apply authorized commit time must equal the signed runtime read-back time"
)
if countersigned_at < authorized_commit_at:
raise PublicationBatchError("apply countersign predates runtime read-back evidence")
if countersigned_at >= approval_expires_at:
raise PublicationBatchError("apply countersign is outside the approval window")
if countersigned_at >= legal_expires_at:
raise PublicationBatchError("apply countersign is outside the legal review window")
if not HEX64_RE.fullmatch(TRUSTED_APPLY_SERVICE_PUBLIC_KEY_SHA256):
raise PublicationBatchError("apply service public key pin is not provisioned")
service_public_raw = _public_key_raw(apply_service_public_key)
if _sha256_bytes(service_public_raw) != TRUSTED_APPLY_SERVICE_PUBLIC_KEY_SHA256:
raise PublicationBatchError("apply service public key does not match the frozen pin")
if service_public_raw == _public_key_raw(approval_root_public_key):
raise PublicationBatchError("apply service key must differ from the approval root key")
service_public_spki = _public_key_spki(apply_service_public_key)
online_public_spki = _public_key_spki(online_service_public_key)
approval_root_spki = _public_key_spki(approval_root_public_key)
if service_public_spki == online_public_spki:
raise PublicationBatchError(
"apply service key must differ from the online transaction service key"
)
if online_public_spki == approval_root_spki:
raise PublicationBatchError(
"online transaction service key must differ from the approval root key"
)
for key in approval_keyring["keys"]:
try:
approval_public_key = serialization.load_pem_public_key(
key["public_key_pem"].encode("ascii")
)
except (KeyError, AttributeError, UnicodeError, ValueError) as exc:
raise PublicationBatchError("approval keyring public key is invalid") from exc
if isinstance(approval_public_key, Ed25519PublicKey) and service_public_spki == _public_key_spki(
approval_public_key
):
raise PublicationBatchError("apply service key must differ from reviewer approval keys")
if (
isinstance(approval_public_key, Ed25519PublicKey)
and online_public_spki == _public_key_spki(approval_public_key)
):
raise PublicationBatchError(
"online transaction service key must differ from reviewer approval keys"
)
try:
signature = base64.b64decode(
_require_string(envelope["signature"], "apply receipt signature", max_length=1024),
validate=True,
)
apply_service_public_key.verify(
signature,
APPLY_SIGNATURE_DOMAIN + _canonical(row),
)
except (TypeError, ValueError, InvalidSignature) as exc:
raise PublicationBatchError("apply service signature verification failed") from exc
expected_id = f"rc06-apply-receipt-{_sha256_bytes(_canonical(row) + signature)[:24]}"
if envelope["receipt_id"] != expected_id:
raise PublicationBatchError("apply receipt_id does not match its signed material")
_assert_no_secret_material(envelope, "apply receipt")
return envelope
def _load_manifest(path: Path, expected_sha256: str | None) -> tuple[dict[str, Any], str]:
payload, raw_sha = secure_read_json(path, "publication batch", expected_sha256)
return validate_manifest(payload), raw_sha
def prepare(args: argparse.Namespace) -> dict[str, Any]:
repo = args.repo.resolve(strict=True)
validate_candidate(repo, args.commit, args.tag)
source_manifest, source_raw_sha = secure_read_json(
args.source_manifest, "source manifest", args.source_manifest_sha256
)
image_payload, image_raw_sha = secure_read_json(
args.image_identities, "image identities", args.image_identities_sha256
)
rc05_payload, rc05_raw_sha = secure_read_json(
args.rc05_plan, "RC-05 plan", args.rc05_plan_sha256
)
rc05_summary, rc05_summary_raw_sha = secure_read_json(
args.rc05_summary, "RC-05 terminal summary", args.rc05_summary_sha256
)
rc05_ledger_identity, rc05_ledger_raw_sha = secure_read_json(
args.rc05_ledger_identity,
"RC-05 ledger identity",
args.rc05_ledger_identity_sha256,
)
rc05_campaign_identity, rc05_campaign_raw_sha = secure_read_json(
args.rc05_campaign_identity,
"RC-05 campaign identity",
args.rc05_campaign_identity_sha256,
)
dispositions_payload = None
if args.golden_dispositions is not None:
dispositions_payload, _ = secure_read_json(
args.golden_dispositions,
"Golden dispositions",
args.golden_dispositions_sha256,
)
elif args.golden_dispositions_sha256 is not None:
raise PublicationBatchError("Golden disposition SHA supplied without a disposition file")
# Determine the complete executable source closure from the frozen Git
# object, verify it before importing any project module, and verify it a
# second time after inventory extraction. This prevents a dirty or
# concurrently swapped worktree module from influencing a candidate that
# claims the immutable commit/tag identity.
frozen_source_paths = _inventory_source_paths(repo, args.commit)
verify_frozen_sources(repo, args.commit, source_manifest, frozen_source_paths)
# Never execute the mutable checkout after it has merely been checked.
# Load the inventory from bytes fetched from the immutable Git object and
# verified against the independently pinned source manifest.
with tempfile.TemporaryDirectory(prefix="yuqei-rc06-frozen-") as temporary:
staged_repo = Path(temporary) / "source"
stage_frozen_sources(
repo,
args.commit,
source_manifest,
frozen_source_paths,
staged_repo,
)
inventory = load_runtime_inventory(
staged_repo,
frozen_source_paths=frozen_source_paths,
)
_, source_payload_sha = _source_manifest_index(source_manifest, args.commit)
image_identity = validate_image_identities(image_payload, args.commit, args.tag)
expected_rc05_candidate = {
"schema_version": RC05_CANDIDATE_SCHEMA_VERSION,
"commit": args.commit,
"tag": args.tag,
"source_manifest": {
"schema_version": "yuqei.release-source-manifest.v1",
"raw_sha256": source_raw_sha,
"payload_sha256": source_payload_sha,
},
"image_identities": {
"schema_version": image_identity["source_schema"],
"raw_sha256": image_raw_sha,
"identity_set_sha256": image_identity["identity_set_sha256"],
"images": image_identity["images"],
},
}
rc05_identity = validate_rc05_plan(
rc05_payload, expected_candidate=expected_rc05_candidate
)
verify_rc05_source_pins(repo, args.commit, source_manifest, rc05_payload)
rc05_terminal_evidence = validate_rc05_terminal_evidence(
rc05_payload,
rc05_raw_sha,
rc05_summary,
rc05_summary_raw_sha,
rc05_ledger_identity,
rc05_ledger_raw_sha,
rc05_campaign_identity,
rc05_campaign_raw_sha,
)
dispositions = build_dispositions(inventory["golden_cases"], dispositions_payload)
manifest = assemble_manifest(
commit=args.commit,
tag=args.tag,
source_manifest_sha256=source_raw_sha,
source_manifest_payload_sha256=source_payload_sha,
image_identities_sha256=image_raw_sha,
image_identity=image_identity,
rc05_plan_sha256=rc05_raw_sha,
rc05_plan_identity=rc05_identity,
rc05_terminal_evidence=rc05_terminal_evidence,
inventory=inventory,
dispositions=dispositions,
)
validate_manifest(manifest)
_safe_output_path(args.output)
raw = json.dumps(manifest, ensure_ascii=False, indent=2, sort_keys=True) + "\n"
try:
with args.output.open("x", encoding="utf-8", newline="\n") as handle:
handle.write(raw)
handle.flush()
os.fsync(handle.fileno())
except FileExistsError as exc:
raise PublicationBatchError(
"output appeared concurrently; refusing to overwrite immutable evidence"
) from exc
return {
"output": str(args.output),
"raw_sha256": _sha256_bytes(raw.encode("utf-8")),
"manifest_payload_sha256": manifest["manifest_payload_sha256"],
"assets": EXPECTED_ASSET_COUNT,
"prompt_modules": EXPECTED_MODULE_COUNT,
"golden_unresolved": manifest["golden_dispositions"]["counts_by_status"]["unresolved"],
"release_ready": False,
"blocked_controls": list(BLOCKED_CONTROLS),
"service_writes": 0,
}
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description=__doc__)
subparsers = parser.add_subparsers(dest="command", required=True)
prepare_parser = subparsers.add_parser("prepare", help="write one offline, fail-closed batch manifest")
prepare_parser.add_argument("--repo", type=Path, default=Path.cwd())
prepare_parser.add_argument("--commit", required=True)
prepare_parser.add_argument("--tag", required=True)
prepare_parser.add_argument("--source-manifest", type=Path, required=True)
prepare_parser.add_argument("--source-manifest-sha256", required=True)
prepare_parser.add_argument("--image-identities", type=Path, required=True)
prepare_parser.add_argument("--image-identities-sha256", required=True)
prepare_parser.add_argument("--rc05-plan", type=Path, required=True)
prepare_parser.add_argument("--rc05-plan-sha256", required=True)
prepare_parser.add_argument("--rc05-summary", type=Path, required=True)
prepare_parser.add_argument("--rc05-summary-sha256", required=True)
prepare_parser.add_argument("--rc05-ledger-identity", type=Path, required=True)
prepare_parser.add_argument("--rc05-ledger-identity-sha256", required=True)
prepare_parser.add_argument("--rc05-campaign-identity", type=Path, required=True)
prepare_parser.add_argument("--rc05-campaign-identity-sha256", required=True)
prepare_parser.add_argument("--golden-dispositions", type=Path)
prepare_parser.add_argument("--golden-dispositions-sha256")
prepare_parser.add_argument("--output", type=Path, required=True)
validate_parser = subparsers.add_parser("validate", help="validate a batch without writing")
validate_parser.add_argument("--manifest", type=Path, required=True)
validate_parser.add_argument("--expected-sha256")
approval_parser = subparsers.add_parser("validate-approval", help="validate a separate approval receipt")
approval_parser.add_argument("--manifest", type=Path, required=True)
approval_parser.add_argument("--manifest-sha256", required=True)
approval_parser.add_argument("--approval", type=Path, required=True)
approval_parser.add_argument("--approval-sha256", required=True)
approval_parser.add_argument("--approval-keyring", type=Path, required=True)
approval_parser.add_argument("--approval-keyring-sha256", required=True)
approval_parser.add_argument("--approval-root-public-key", type=Path, required=True)
apply_parser = subparsers.add_parser("validate-apply", help="validate a separate apply receipt")
apply_parser.add_argument("--manifest", type=Path, required=True)
apply_parser.add_argument("--manifest-sha256", required=True)
apply_parser.add_argument("--approval", type=Path, required=True)
apply_parser.add_argument("--approval-sha256", required=True)
apply_parser.add_argument("--approval-keyring", type=Path, required=True)
apply_parser.add_argument("--approval-keyring-sha256", required=True)
apply_parser.add_argument("--approval-root-public-key", type=Path, required=True)
apply_parser.add_argument("--apply-service-public-key", type=Path, required=True)
apply_parser.add_argument("--online-service-public-key", type=Path, required=True)
apply_parser.add_argument("--legal-review-binding-sha256", required=True)
apply_parser.add_argument("--legal-review-expires-at", required=True)
apply_parser.add_argument("--environment-id", required=True)
apply_parser.add_argument("--tenant-id", required=True)
apply_parser.add_argument("--apply-receipt", type=Path, required=True)
apply_parser.add_argument("--apply-receipt-sha256", required=True)
args = parser.parse_args(argv)
try:
if args.command == "prepare":
result = prepare(args)
elif args.command == "validate":
manifest, raw_sha = _load_manifest(args.manifest, args.expected_sha256)
result = {
"structurally_valid": True,
"raw_sha256": raw_sha,
"manifest_payload_sha256": manifest["manifest_payload_sha256"],
"evidence_complete": False,
"release_ready": False,
"blocked_controls": list(BLOCKED_CONTROLS),
"service_writes": 0,
}
elif args.command == "validate-approval":
manifest, manifest_raw_sha = _load_manifest(args.manifest, args.manifest_sha256)
approval, raw_sha = secure_read_json(args.approval, "approval receipt", args.approval_sha256)
approval_keyring, _ = secure_read_json(
args.approval_keyring,
"approval keyring",
args.approval_keyring_sha256,
)
approval_root_public_key = _read_pinned_raw_public_key(
args.approval_root_public_key,
expected_sha256=TRUSTED_APPROVAL_ROOT_PUBLIC_KEY_SHA256,
label="approval root public key",
)
validate_approval_receipt(
manifest,
manifest_raw_sha,
approval,
approval_keyring,
approval_root_public_key,
)
result = {
"structurally_valid": True,
"approval_raw_sha256": raw_sha,
"evidence_complete": False,
"release_ready": False,
"blocked_controls": list(BLOCKED_CONTROLS[1:]),
"service_writes": 0,
}
else:
manifest, manifest_raw_sha = _load_manifest(args.manifest, args.manifest_sha256)
approval, approval_raw = secure_read_json(
args.approval, "approval receipt", args.approval_sha256
)
approval_keyring, _ = secure_read_json(
args.approval_keyring,
"approval keyring",
args.approval_keyring_sha256,
)
approval_root_public_key = _read_pinned_raw_public_key(
args.approval_root_public_key,
expected_sha256=TRUSTED_APPROVAL_ROOT_PUBLIC_KEY_SHA256,
label="approval root public key",
)
apply_service_public_key = _read_pinned_raw_public_key(
args.apply_service_public_key,
expected_sha256=TRUSTED_APPLY_SERVICE_PUBLIC_KEY_SHA256,
label="apply service public key",
)
online_service_public_key = _read_pinned_spki_public_key(
args.online_service_public_key,
expected_sha256=TRUSTED_ONLINE_APPLY_SERVICE_PUBLIC_KEY_SPKI_SHA256,
label="online publication service public key",
)
validate_approval_receipt(
manifest,
manifest_raw_sha,
approval,
approval_keyring,
approval_root_public_key,
)
apply_receipt, apply_raw = secure_read_json(
args.apply_receipt, "apply receipt", args.apply_receipt_sha256
)
validate_apply_receipt(
manifest,
manifest_raw_sha,
approval,
approval_keyring,
approval_root_public_key,
apply_service_public_key,
online_service_public_key,
approval_raw,
apply_receipt,
legal_review_binding_sha256=args.legal_review_binding_sha256,
legal_review_expires_at=args.legal_review_expires_at,
environment_id=args.environment_id,
tenant_id=args.tenant_id,
)
result = {
"structurally_valid": True,
"apply_receipt_raw_sha256": apply_raw,
"evidence_complete": True,
"release_ready": False,
"blocked_controls": [],
"evidence_scope": "rc06_publication_only",
"service_writes": 0,
}
except PublicationBatchError as exc:
print(f"publication_batch_error: {exc}", file=sys.stderr)
return 2
print(json.dumps(result, ensure_ascii=False, sort_keys=True))
return 0
if __name__ == "__main__":
raise SystemExit(main())