"""Declarative, fail-closed, project-level content publisher. The only user-visible commit point is an existing Markdown cases current index. Immutable release members are prepared first; the Markdown index is replaced atomically last. The result-side Markdown entry remains an invariant thin link. No industry, batch, task, run, release, or attempt identity is hard-coded here. """ from __future__ import annotations import argparse import csv import hashlib import io import json import os import stat import sys import time import uuid from dataclasses import dataclass from datetime import datetime, timedelta, timezone from pathlib import Path from typing import Any, Iterable CONFIG_SCHEMA = "SHARED_CONTENT_PUBLISHER_CONFIG_V2" DIRECT_CONFIG_SCHEMA = "SHARED_CONTENT_PUBLISHER_CONFIG_V3" TERMINAL_SCHEMA = "SHARED_CONTENT_PUBLISHER_TERMINAL_V3" EVENT_CHAIN_SCHEMA = "SHARED_CONTENT_PUBLISHER_ATTEMPT_EVENT_CHAIN_V1" COMMIT_STRATEGY = "MARKDOWN_CURRENT_INDEX_REPLACE_V1" DIRECT_COMMIT_STRATEGY = "DIRECT_STABLE_PATH_SET_V1" LEDGER_HEADER = [ "release_id", "event_seq", "state", "prior_release_id", "prior_release_set_sha256", "candidate_release_set_sha256", "task_id", "case_id", "batch_id", "run_id", "accepted_audit_id", "operator", "process_identity", "event_time", "recovery_or_rollback_receipt", "attempt_id", "attempt_seq", ] SUCCESS_STATES = ("PREPARED", "VERIFIED", "COMMITTING", "COMMITTED") HEX64 = set("0123456789ABCDEF") class PublisherError(Exception): """A classified publisher failure.""" def __init__(self, code: str, detail: str, *, exit_code: int = 12) -> None: super().__init__(f"{code}:{detail}") self.code = code self.detail = detail self.exit_code = exit_code def _pairs_no_duplicates(pairs: list[tuple[str, Any]]) -> dict[str, Any]: result: dict[str, Any] = {} for key, value in pairs: if key in result: raise PublisherError("CONFIG_DUPLICATE_KEY", key) result[key] = value return result def _load_config(path: Path) -> tuple[dict[str, Any], bytes]: data = _read_bytes(path) if data.startswith(b"\xef\xbb\xbf") or b"\x00" in data: raise PublisherError("CONFIG_ENCODING", "BOM/NUL forbidden") try: value = json.loads(data.decode("utf-8"), object_pairs_hook=_pairs_no_duplicates) except PublisherError: raise except Exception as exc: raise PublisherError("CONFIG_PARSE", str(exc)) from exc if not isinstance(value, dict): raise PublisherError("CONFIG_TYPE", "root must be object") return value, data def _expect_keys(value: dict[str, Any], expected: Iterable[str], where: str) -> None: expected_set = set(expected) actual = set(value) missing = sorted(expected_set - actual) extra = sorted(actual - expected_set) if missing or extra: raise PublisherError("CONFIG_KEYS", f"{where}:missing={missing};extra={extra}") def _need_string(value: Any, where: str) -> str: if not isinstance(value, str) or not value: raise PublisherError("CONFIG_TYPE", f"{where} must be nonempty string") return value def _need_int(value: Any, where: str, *, positive: bool = False) -> int: if isinstance(value, bool) or not isinstance(value, int) or (positive and value <= 0): raise PublisherError("CONFIG_TYPE", f"{where} must be integer") return value def _need_sha(value: Any, where: str, *, lower: bool = False) -> str: text = _need_string(value, where) expected = text.lower() if lower else text.upper() alphabet = set("0123456789abcdef") if lower else HEX64 if text != expected or len(text) != 64 or any(ch not in alphabet for ch in text): raise PublisherError("CONFIG_SHA256", where) return text def _long(path: Path | str) -> str: text = os.path.abspath(os.fspath(path)) if os.name != "nt" or text.startswith("\\\\?\\"): return text if text.startswith("\\\\"): return "\\\\?\\UNC\\" + text[2:] return "\\\\?\\" + text def _lstat(path: Path | str) -> os.stat_result: return os.stat(_long(path), follow_symlinks=False) def _exists(path: Path | str) -> bool: try: _lstat(path) return True except FileNotFoundError: return False def _is_reparse(st: os.stat_result) -> bool: return bool(getattr(st, "st_file_attributes", 0) & 0x400) or stat.S_ISLNK(st.st_mode) def _ordinary_file(path: Path | str) -> os.stat_result: try: st = _lstat(path) except OSError as exc: raise PublisherError("FILE_UNREADABLE", f"{path}:{exc}") from exc if not stat.S_ISREG(st.st_mode) or _is_reparse(st): raise PublisherError("FILE_NOT_ORDINARY", str(path)) return st def _ordinary_dir(path: Path | str) -> os.stat_result: try: st = _lstat(path) except OSError as exc: raise PublisherError("DIR_UNREADABLE", f"{path}:{exc}") from exc if not stat.S_ISDIR(st.st_mode) or _is_reparse(st): raise PublisherError("DIR_NOT_ORDINARY", str(path)) return st def _read_bytes(path: Path | str) -> bytes: _ordinary_file(path) try: with open(_long(path), "rb") as handle: return handle.read() except OSError as exc: raise PublisherError("FILE_UNREADABLE", f"{path}:{exc}") from exc def _sha_bytes(data: bytes) -> str: return hashlib.sha256(data).hexdigest().upper() def _identity(path: Path | str) -> tuple[int, str]: data = _read_bytes(path) if not data: raise PublisherError("FILE_EMPTY", str(path)) return len(data), _sha_bytes(data) def _identity_independent(path: Path | str) -> tuple[int, str]: _ordinary_file(path) total = 0 digest = hashlib.sha256() try: with open(_long(path), "rb", buffering=0) as handle: while True: chunk = handle.read(131072) if not chunk: break total += len(chunk) digest.update(chunk) except OSError as exc: raise PublisherError("FILE_UNREADABLE", f"{path}:{exc}") from exc if total <= 0: raise PublisherError("FILE_EMPTY", str(path)) return total, digest.hexdigest().upper() def _canonical_json(value: Any, *, newline: bool = True) -> bytes: data = json.dumps(value, ensure_ascii=False, separators=(",", ":"), sort_keys=True).encode("utf-8") return data + (b"\n" if newline else b"") def _utc_now() -> str: return datetime.now(timezone.utc).isoformat(timespec="microseconds").replace("+00:00", "Z") def _parse_strict_utc(value: str, code: str) -> datetime: if not isinstance(value, str) or not value.endswith("Z"): raise PublisherError(code, str(value), exit_code=27) try: parsed = datetime.fromisoformat(value[:-1] + "+00:00") except ValueError as exc: raise PublisherError(code, value, exit_code=27) from exc canonical = parsed.astimezone(timezone.utc).isoformat(timespec="microseconds").replace("+00:00", "Z") if parsed.utcoffset() != timezone.utc.utcoffset(parsed) or canonical != value: raise PublisherError(code, value, exit_code=27) return parsed def _safe_relative(value: Any, where: str) -> str: text = _need_string(value, where).replace("\\", "/") if text.startswith("/") or Path(text).is_absolute() or any(part in ("", ".", "..") for part in text.split("/")): raise PublisherError("PATH_RELATIVE", where) return text def _norm(path: Path | str) -> str: return os.path.normcase(os.path.abspath(os.fspath(path))).casefold() def _inside(root: Path, relative: str) -> Path: candidate = Path(os.path.abspath(os.path.join(root, *relative.split("/")))) if os.path.commonpath([_norm(root), _norm(candidate)]) != _norm(root): raise PublisherError("PATH_ESCAPE", relative) return candidate def _volume(path: Path) -> str: drive, _ = os.path.splitdrive(os.path.abspath(path)) return drive.upper() if drive else str(_lstat(path).st_dev) def _physical_chain(path: Path, *, final_kind: str | None = None) -> None: """Reject every existing reparse/alias component from the volume root down.""" absolute = Path(os.path.abspath(path)) anchor = Path(absolute.anchor) current = anchor parts = absolute.parts[1:] if absolute.anchor else absolute.parts if _exists(anchor): _ordinary_dir(anchor) for index, part in enumerate(parts): current = current / part if not _exists(current): break st = _lstat(current) if _is_reparse(st): raise PublisherError("PATH_REPARSE", str(current)) is_final = index == len(parts) - 1 if not is_final or final_kind == "dir": if not stat.S_ISDIR(st.st_mode): raise PublisherError("PATH_ANCESTOR_TYPE", str(current)) elif final_kind == "file" and not stat.S_ISREG(st.st_mode): raise PublisherError("PATH_FINAL_TYPE", str(current)) if _norm(os.path.realpath(current)) != _norm(current): raise PublisherError("PATH_ALIAS", str(current)) def _validate_parent_chain(root: Path, path: Path, *, final_kind: str | None = None) -> None: if os.path.commonpath([_norm(root), _norm(path)]) != _norm(root): raise PublisherError("PATH_OUTSIDE_ROOT", str(path)) _physical_chain(path, final_kind=final_kind) def _overlap(first: Path, second: Path) -> bool: a, b = _norm(first), _norm(second) return os.path.commonpath([a, b]) in (a, b) def _validate_path_graph(paths: dict[str, Path], allowed: set[frozenset[str]]) -> None: names = sorted(paths) for index, left in enumerate(names): for right in names[index + 1:]: if _overlap(paths[left], paths[right]) and frozenset((left, right)) not in allowed: raise PublisherError("PATH_OVERLAP", f"{left}<->{right}") def _walk_files(root: Path) -> list[str]: _ordinary_dir(root) found: list[str] = [] def visit(current: Path, relative: str) -> None: try: entries = sorted(os.scandir(_long(current)), key=lambda item: item.name.casefold()) except OSError as exc: raise PublisherError("TREE_UNREADABLE", f"{current}:{exc}") from exc for entry in entries: rel = f"{relative}/{entry.name}" if relative else entry.name st = entry.stat(follow_symlinks=False) if _is_reparse(st): raise PublisherError("TREE_REPARSE", rel) if stat.S_ISDIR(st.st_mode): visit(current / entry.name, rel) elif stat.S_ISREG(st.st_mode): found.append(rel.replace("\\", "/")) else: raise PublisherError("TREE_OBJECT_TYPE", rel) visit(root, "") return found @dataclass(frozen=True) class ArtifactRow: member_id: str relative_path: str formal_relative_path: str artifact_type: str commit_role: str bytes: int sha256: str @dataclass(frozen=True) class FormalRow: member_id: str formal_relative_path: str artifact_type: str bytes: int sha256: str def _parse_artifact_rows(value: Any, where: str) -> tuple[ArtifactRow, ...]: if not isinstance(value, list) or not value: raise PublisherError("CONFIG_TYPE", f"{where} must be nonempty array") rows: list[ArtifactRow] = [] member_ids: set[str] = set() sources: set[str] = set() formals: set[str] = set() keys = {"member_id", "relative_path", "formal_relative_path", "artifact_type", "commit_role", "bytes", "sha256"} for index, item in enumerate(value): if not isinstance(item, dict): raise PublisherError("CONFIG_TYPE", f"{where}[{index}]") _expect_keys(item, keys, f"{where}[{index}]") member = _need_string(item["member_id"], f"{where}[{index}].member_id") source = _safe_relative(item["relative_path"], f"{where}[{index}].relative_path") formal = _safe_relative(item["formal_relative_path"], f"{where}[{index}].formal_relative_path") artifact = _need_string(item["artifact_type"], f"{where}[{index}].artifact_type") role = _need_string(item["commit_role"], f"{where}[{index}].commit_role") if role not in ("RELEASE_MEMBER", "CASE_CURRENT_INDEX"): raise PublisherError("CONFIG_ENUM", f"{where}[{index}].commit_role") size = _need_int(item["bytes"], f"{where}[{index}].bytes", positive=True) digest = _need_sha(item["sha256"], f"{where}[{index}].sha256") if member in member_ids or source in sources or formal.casefold() in formals: raise PublisherError("CONFIG_DUPLICATE_ROW", f"{where}[{index}]") member_ids.add(member) sources.add(source) formals.add(formal.casefold()) rows.append(ArtifactRow(member, source, formal, artifact, role, size, digest)) return tuple(rows) def _parse_formal_rows(value: Any, where: str) -> tuple[FormalRow, ...]: if not isinstance(value, list) or not value: raise PublisherError("CONFIG_TYPE", f"{where} must be nonempty array") rows: list[FormalRow] = [] seen_members: set[str] = set() seen_paths: set[str] = set() keys = {"member_id", "formal_relative_path", "artifact_type", "bytes", "sha256"} for index, item in enumerate(value): if not isinstance(item, dict): raise PublisherError("CONFIG_TYPE", f"{where}[{index}]") _expect_keys(item, keys, f"{where}[{index}]") member = _need_string(item["member_id"], f"{where}[{index}].member_id") formal = _safe_relative(item["formal_relative_path"], f"{where}[{index}].formal_relative_path") artifact = _need_string(item["artifact_type"], f"{where}[{index}].artifact_type") size = _need_int(item["bytes"], f"{where}[{index}].bytes", positive=True) digest = _need_sha(item["sha256"], f"{where}[{index}].sha256") if member in seen_members or formal.casefold() in seen_paths: raise PublisherError("CONFIG_DUPLICATE_ROW", f"{where}[{index}]") seen_members.add(member) seen_paths.add(formal.casefold()) rows.append(FormalRow(member, formal, artifact, size, digest)) return tuple(rows) def _parse_history_rows(value: Any, where: str) -> tuple[tuple[str, int, str], ...]: if not isinstance(value, list) or not value: raise PublisherError("CONFIG_TYPE", f"{where} must be nonempty array") result: list[tuple[str, int, str]] = [] seen: set[str] = set() for index, item in enumerate(value): if not isinstance(item, dict): raise PublisherError("CONFIG_TYPE", f"{where}[{index}]") _expect_keys(item, {"relative_path", "bytes", "sha256"}, f"{where}[{index}]") rel = _safe_relative(item["relative_path"], f"{where}[{index}].relative_path") size = _need_int(item["bytes"], f"{where}[{index}].bytes", positive=True) digest = _need_sha(item["sha256"], f"{where}[{index}].sha256") if rel.casefold() in seen: raise PublisherError("CONFIG_DUPLICATE_ROW", f"{where}[{index}]") seen.add(rel.casefold()) result.append((rel, size, digest)) return tuple(result) def _verify_identity(path: Path, size: int, digest: str, code: str) -> None: first = _identity(path) second = _identity_independent(path) if first != second or first != (size, digest): raise PublisherError(code, str(path)) def _verify_history(root: Path, rows: tuple[tuple[str, int, str], ...], threshold: int, minimum: int) -> None: expected = {row[0] for row in rows} actual = set(_walk_files(root)) if actual != expected: raise PublisherError("HISTORY_EXACT_SET", f"missing={sorted(expected-actual)};extra={sorted(actual-expected)}") long_count = 0 for rel, size, digest in rows: path = _inside(root, rel) _verify_identity(path, size, digest, "HISTORY_IDENTITY") if len(os.path.abspath(path)) >= threshold: long_count += 1 if long_count < minimum: raise PublisherError("HISTORY_LONG_PATH_COUNT", f"{long_count}<{minimum}") def _manifest_rows(data: bytes, *, candidate: bool) -> list[dict[str, str]]: header = (["member_id", "candidate_relative_path", "formal_relative_path", "artifact_type", "bytes", "sha256"] if candidate else ["member_id", "formal_relative_path", "artifact_type", "bytes", "sha256"]) try: reader = csv.DictReader(io.StringIO(data.decode("utf-8-sig"), newline="")) if reader.fieldnames != header: raise PublisherError("MANIFEST_HEADER", str(reader.fieldnames)) rows = list(reader) except PublisherError: raise except Exception as exc: raise PublisherError("MANIFEST_PARSE", str(exc)) from exc if not rows or any(None in row for row in rows): raise PublisherError("MANIFEST_ROWS", "empty or malformed") ids: set[str] = set() paths: set[str] = set() for row in rows: member = row["member_id"] formal = row["formal_relative_path"].replace("\\", "/").casefold() if not member or member in ids or not formal or formal in paths: raise PublisherError("MANIFEST_DUPLICATE", member or formal) try: if int(row["bytes"]) <= 0: raise ValueError except ValueError as exc: raise PublisherError("MANIFEST_BYTES", member) from exc _need_sha(row["sha256"], f"manifest.{member}.sha256") ids.add(member) paths.add(formal) return rows def _formal_tuple(row: FormalRow) -> tuple[str, str, str, int, str]: return row.member_id, row.formal_relative_path, row.artifact_type, row.bytes, row.sha256 def _artifact_formal_tuple(row: ArtifactRow) -> tuple[str, str, str, int, str]: return row.member_id, row.formal_relative_path, row.artifact_type, row.bytes, row.sha256 def _manifest_tuple(row: dict[str, str]) -> tuple[str, str, str, int, str]: return row["member_id"], row["formal_relative_path"].replace("\\", "/"), row["artifact_type"], int(row["bytes"]), row["sha256"] def _release_set(data: bytes, self_path: str) -> str: descriptor = _canonical_json({"bytes": len(data), "formal_relative_path": self_path, "sha256": _sha_bytes(data)}, newline=False) return _sha_bytes(data + descriptor) def _parse_checks(value: Any, where: str) -> tuple[tuple[str, tuple[str, ...]], ...]: if not isinstance(value, list) or not value: raise PublisherError("CONFIG_TYPE", f"{where} must be nonempty array") result: list[tuple[str, tuple[str, ...]]] = [] for index, item in enumerate(value): if not isinstance(item, dict): raise PublisherError("CONFIG_TYPE", f"{where}[{index}]") _expect_keys(item, {"relative_path", "required_utf8_substrings"}, f"{where}[{index}]") rel = _safe_relative(item["relative_path"], f"{where}[{index}].relative_path") required = item["required_utf8_substrings"] if not isinstance(required, list) or not required: raise PublisherError("CONFIG_TYPE", f"{where}[{index}].required_utf8_substrings") strings = tuple(_need_string(text, f"{where}[{index}].required_utf8_substrings") for text in required) result.append((rel, strings)) return tuple(result) def _verify_checks(root: Path, checks: tuple[tuple[str, tuple[str, ...]], ...], code: str) -> None: for rel, required in checks: try: text = _read_bytes(_inside(root, rel)).decode("utf-8") except UnicodeDecodeError as exc: raise PublisherError(code, f"{rel}:UTF8") from exc for needle in required: if needle not in text: raise PublisherError(code, f"{rel}:{needle}") def _read_ledger(data: bytes) -> list[dict[str, str]]: try: reader = csv.DictReader(io.StringIO(data.decode("utf-8-sig"), newline="")) if reader.fieldnames != LEDGER_HEADER: raise PublisherError("LEDGER_HEADER", str(reader.fieldnames)) rows = list(reader) except PublisherError: raise except Exception as exc: raise PublisherError("LEDGER_PARSE", str(exc)) from exc sequences: set[int] = set() for row in rows: if set(row) != set(LEDGER_HEADER) or any(not isinstance(row[key], str) for key in LEDGER_HEADER): raise PublisherError("LEDGER_ROW_SHAPE", str(row)) try: sequence = int(row["event_seq"]) attempt_seq = int(row["attempt_seq"]) except (TypeError, ValueError) as exc: raise PublisherError("LEDGER_INTEGER", str(row)) from exc if sequence <= 0 or attempt_seq <= 0 or sequence in sequences: raise PublisherError("LEDGER_SEQUENCE_UNIQUE", str(sequence)) sequences.add(sequence) return rows def _derive_sequences(rows: list[dict[str, str]], identity: dict[str, str]) -> tuple[int, int]: next_event = max((int(row["event_seq"]) for row in rows), default=0) + 1 matching = [int(row["attempt_seq"]) for row in rows if all(row[key] == identity[key] for key in ("task_id", "case_id", "batch_id", "run_id"))] return next_event, max(matching, default=0) + 1 def _event_rows_for_attempt(rows: list[dict[str, str]], attempt: str) -> list[dict[str, str]]: return sorted((row for row in rows if row["attempt_id"] == attempt), key=lambda row: int(row["event_seq"])) def _event_chain_digest(rows: list[dict[str, str]]) -> str: payload = { "columns": LEDGER_HEADER, "rows": [[row[column] for column in LEDGER_HEADER] for row in rows], "schema_version": EVENT_CHAIN_SCHEMA, } return _sha_bytes(_canonical_json(payload, newline=False)) @dataclass class Plan: config: dict[str, Any] config_path: Path config_data: bytes config_sha256: str operation_root: Path identity: dict[str, str] paths: dict[str, Path] candidate_rows: tuple[ArtifactRow, ...] prior_rows: tuple[FormalRow, ...] history_rows: tuple[tuple[str, int, str], ...] link_checks: tuple[tuple[str, tuple[str, ...]], ...] evidence_checks: tuple[tuple[str, tuple[str, ...]], ...] ledger_base_data: bytes next_event_seq: int next_attempt_seq: int prior_index_data: bytes candidate_index_data: bytes target_release_relative: str target_rows: tuple[ArtifactRow, ...] manifest_row: ArtifactRow result_row: FormalRow prior_release_set: str lifecycle: str def _verify_prior_manifest(plan_root: Path, prior: dict[str, Any], rows: tuple[FormalRow, ...]) -> tuple[bytes, str]: _expect_keys(prior, {"release_id", "manifest_formal_relative_path", "manifest_bytes", "manifest_sha256", "manifest_self_formal_relative_path", "release_set_sha256", "rows"}, "expected.prior") _need_sha(prior["release_id"], "expected.prior.release_id", lower=True) manifest_rel = _safe_relative(prior["manifest_formal_relative_path"], "expected.prior.manifest_formal_relative_path") self_rel = _safe_relative(prior["manifest_self_formal_relative_path"], "expected.prior.manifest_self_formal_relative_path") if manifest_rel.casefold() != self_rel.casefold(): raise PublisherError("PRIOR_MANIFEST_SELF_PATH", f"{manifest_rel}!={self_rel}") data = _read_bytes(_inside(plan_root, manifest_rel)) expected_id = (_need_int(prior["manifest_bytes"], "expected.prior.manifest_bytes", positive=True), _need_sha(prior["manifest_sha256"], "expected.prior.manifest_sha256")) if (len(data), _sha_bytes(data)) != expected_id: raise PublisherError("PRIOR_MANIFEST_IDENTITY", manifest_rel) actual = {_manifest_tuple(row) for row in _manifest_rows(data, candidate=False)} expected = {_formal_tuple(row) for row in rows} if actual != expected or len(actual) != len(rows): raise PublisherError("PRIOR_MANIFEST_COVERAGE", f"actual={len(actual)};expected={len(expected)}") release_set = _release_set(data, self_rel) if release_set != _need_sha(prior["release_set_sha256"], "expected.prior.release_set_sha256"): raise PublisherError("PRIOR_RELEASE_SET", release_set) return data, release_set def _validate_config(config: dict[str, Any], config_path: Path, config_data: bytes) -> Plan: _expect_keys(config, {"schema_version", "identity", "roots", "expected", "commit", "test_control"}, "root") if config["schema_version"] != CONFIG_SCHEMA: raise PublisherError("CONFIG_SCHEMA", str(config["schema_version"])) for name in ("identity", "roots", "expected", "commit", "test_control"): if not isinstance(config[name], dict): raise PublisherError("CONFIG_TYPE", name) identity = config["identity"] identity_keys = {"industry", "task_id", "case_id", "batch_id", "run_id", "attempt_id", "canonical_audit_id", "review_handoff_id", "release_id", "prior_release_id", "candidate_release_set_sha256", "operator"} _expect_keys(identity, identity_keys, "identity") for key in identity_keys: _need_string(identity[key], f"identity.{key}") if not identity["canonical_audit_id"].startswith("AUDIT-"): raise PublisherError("AUDIT_ID_DOMAIN", identity["canonical_audit_id"]) if not identity["review_handoff_id"].startswith("HANDOFF-"): raise PublisherError("HANDOFF_ID_DOMAIN", identity["review_handoff_id"]) if identity["canonical_audit_id"] == identity["review_handoff_id"]: raise PublisherError("AUDIT_HANDOFF_AMBIGUOUS", "equal identities") _need_sha(identity["release_id"], "identity.release_id", lower=True) _need_sha(identity["prior_release_id"], "identity.prior_release_id", lower=True) _need_sha(identity["candidate_release_set_sha256"], "identity.candidate_release_set_sha256") preimage = "".join(f"{key}={identity[key]}\n" for key in ("industry", "task_id", "case_id", "batch_id", "run_id", "canonical_audit_id")) if hashlib.sha256(preimage.encode("utf-8")).hexdigest() != identity["release_id"]: raise PublisherError("RELEASE_PREIMAGE", "release id mismatch") roots = config["roots"] root_keys = {"operation_root", "resolved_root", "volume_identity", "candidate_root", "release_store_root", "case_current_index_path", "result_current_index_path", "ledger_path", "lock_path", "attempt_receipt_root", "history_root", "current_state_relative_path"} _expect_keys(roots, root_keys, "roots") operation_root = Path(os.path.abspath(_need_string(roots["operation_root"], "roots.operation_root"))) _physical_chain(operation_root, final_kind="dir") _ordinary_dir(operation_root) if _norm(operation_root) != _norm(_need_string(roots["resolved_root"], "roots.resolved_root")): raise PublisherError("ROOT_RESOLUTION", str(operation_root)) volume = _need_string(roots["volume_identity"], "roots.volume_identity").upper() if _volume(operation_root).upper() != volume: raise PublisherError("VOLUME_IDENTITY", volume) if os.path.commonpath([_norm(operation_root), _norm(config_path)]) != _norm(operation_root): raise PublisherError("CONFIG_OUTSIDE_ROOT", str(config_path)) paths: dict[str, Path] = {} for key in ("candidate_root", "release_store_root", "case_current_index_path", "result_current_index_path", "ledger_path", "lock_path", "attempt_receipt_root", "history_root"): paths[key] = _inside(operation_root, _safe_relative(roots[key], f"roots.{key}")) history_state_rel = _safe_relative(roots["current_state_relative_path"], "roots.current_state_relative_path") paths["current_state_path"] = _inside(paths["history_root"], history_state_rel) for key in ("candidate_root", "release_store_root", "history_root"): _validate_parent_chain(operation_root, paths[key], final_kind="dir") _ordinary_dir(paths[key]) if _volume(paths[key]).upper() != volume: raise PublisherError("VOLUME_DRIFT", key) for key in ("case_current_index_path", "result_current_index_path", "ledger_path", "current_state_path"): _validate_parent_chain(operation_root, paths[key], final_kind="file") _ordinary_file(paths[key]) for key in ("lock_path", "attempt_receipt_root"): _validate_parent_chain(operation_root, paths[key]) _validate_parent_chain(operation_root, config_path, final_kind="file") commit = config["commit"] _expect_keys(commit, {"strategy", "target_release_relative_path", "staging_relative_path"}, "commit") if commit["strategy"] != COMMIT_STRATEGY: raise PublisherError("COMMIT_STRATEGY", str(commit["strategy"])) target_rel = _safe_relative(commit["target_release_relative_path"], "commit.target_release_relative_path") stage_rel = _safe_relative(commit["staging_relative_path"], "commit.staging_relative_path") paths["target_release"] = _inside(operation_root, target_rel) paths["staging"] = _inside(operation_root, stage_rel) paths["snapshot"] = paths["attempt_receipt_root"] / "prior_snapshot" for key in ("target_release", "staging", "snapshot"): _validate_parent_chain(operation_root, paths[key]) if os.path.commonpath([_norm(paths["release_store_root"]), _norm(paths["target_release"])]) != _norm(paths["release_store_root"]): raise PublisherError("TARGET_RELEASE_STORE", target_rel) if os.path.commonpath([_norm(paths["release_store_root"]), _norm(paths["staging"])]) != _norm(paths["release_store_root"]): raise PublisherError("STAGING_RELEASE_STORE", stage_rel) path_graph = {key: paths[key] for key in ("candidate_root", "release_store_root", "case_current_index_path", "result_current_index_path", "ledger_path", "lock_path", "attempt_receipt_root", "history_root", "target_release", "staging", "snapshot")} path_graph["config_path"] = config_path _validate_path_graph(path_graph, {frozenset(("release_store_root", "target_release")), frozenset(("release_store_root", "staging")), frozenset(("attempt_receipt_root", "snapshot"))}) if _exists(paths["lock_path"]): raise PublisherError("LOCK_OCCUPIED", str(paths["lock_path"])) expected = config["expected"] _expect_keys(expected, {"ledger", "candidate", "prior", "history", "case_current_index", "result_current_index", "current_state"}, "expected") candidate = expected["candidate"] if not isinstance(candidate, dict): raise PublisherError("CONFIG_TYPE", "expected.candidate") candidate_keys = {"manifest_relative_path", "manifest_bytes", "manifest_sha256", "current_manifest_relative_path", "current_manifest_bytes", "current_manifest_sha256", "manifest_self_formal_relative_path", "rows", "link_checks", "evidence_checks"} _expect_keys(candidate, candidate_keys, "expected.candidate") candidate_rows = _parse_artifact_rows(candidate["rows"], "expected.candidate.rows") target_rows = tuple(row for row in candidate_rows if row.commit_role == "RELEASE_MEMBER") index_rows = tuple(row for row in candidate_rows if row.commit_role == "CASE_CURRENT_INDEX") if len(index_rows) != 1 or not target_rows: raise PublisherError("CANDIDATE_COMMIT_ROLES", f"release={len(target_rows)};index={len(index_rows)}") candidate_index = index_rows[0] case_formal = os.path.relpath(paths["case_current_index_path"], operation_root).replace("\\", "/") if candidate_index.formal_relative_path.casefold() != case_formal.casefold(): raise PublisherError("CASE_INDEX_FORMAL_PATH", candidate_index.formal_relative_path) target_prefix = target_rel.rstrip("/") + "/" for row in target_rows: if not row.formal_relative_path.casefold().startswith(target_prefix.casefold()): raise PublisherError("TARGET_MEMBER_PATH", row.formal_relative_path) formal_tail = [row.formal_relative_path[len(target_prefix):].casefold() for row in target_rows] if len(formal_tail) != len(set(formal_tail)) or any(not tail for tail in formal_tail): raise PublisherError("TARGET_MEMBER_DUPLICATE", str(formal_tail)) manifest_rel = _safe_relative(candidate["manifest_relative_path"], "expected.candidate.manifest_relative_path") manifest_data = _read_bytes(_inside(paths["candidate_root"], manifest_rel)) if (len(manifest_data), _sha_bytes(manifest_data)) != (_need_int(candidate["manifest_bytes"], "expected.candidate.manifest_bytes", positive=True), _need_sha(candidate["manifest_sha256"], "expected.candidate.manifest_sha256")): raise PublisherError("CANDIDATE_MANIFEST_IDENTITY", manifest_rel) manifest_actual = [] for row in _manifest_rows(manifest_data, candidate=True): manifest_actual.append((row["member_id"], row["candidate_relative_path"].removeprefix("candidate/").replace("\\", "/"), row["formal_relative_path"].replace("\\", "/"), row["artifact_type"], int(row["bytes"]), row["sha256"])) manifest_expected = [(row.member_id, row.relative_path, row.formal_relative_path, row.artifact_type, row.bytes, row.sha256) for row in candidate_rows] if manifest_actual != manifest_expected: raise PublisherError("CANDIDATE_MANIFEST_BINDING", "ordered rows differ") exact_candidate = {manifest_rel} | {row.relative_path for row in candidate_rows} actual_candidate = set(_walk_files(paths["candidate_root"])) if actual_candidate != exact_candidate: raise PublisherError("CANDIDATE_EXACT_SET", f"missing={sorted(exact_candidate-actual_candidate)};extra={sorted(actual_candidate-exact_candidate)}") for row in candidate_rows: _verify_identity(_inside(paths["candidate_root"], row.relative_path), row.bytes, row.sha256, "CANDIDATE_IDENTITY") current_manifest_rel = _safe_relative(candidate["current_manifest_relative_path"], "expected.candidate.current_manifest_relative_path") manifest_matches = [row for row in target_rows if row.relative_path.casefold() == current_manifest_rel.casefold()] if len(manifest_matches) != 1: raise PublisherError("CURRENT_MANIFEST_ROW", str(len(manifest_matches))) manifest_row = manifest_matches[0] self_formal = _safe_relative(candidate["manifest_self_formal_relative_path"], "expected.candidate.manifest_self_formal_relative_path") if self_formal.casefold() != manifest_row.formal_relative_path.casefold(): raise PublisherError("CURRENT_MANIFEST_SELF_PATH", f"{self_formal}!={manifest_row.formal_relative_path}") current_manifest_data = _read_bytes(_inside(paths["candidate_root"], current_manifest_rel)) if (len(current_manifest_data), _sha_bytes(current_manifest_data)) != (_need_int(candidate["current_manifest_bytes"], "expected.candidate.current_manifest_bytes", positive=True), _need_sha(candidate["current_manifest_sha256"], "expected.candidate.current_manifest_sha256")): raise PublisherError("CURRENT_MANIFEST_IDENTITY", current_manifest_rel) result_expected = expected["result_current_index"] if not isinstance(result_expected, dict): raise PublisherError("CONFIG_TYPE", "expected.result_current_index") _expect_keys(result_expected, {"member_id", "formal_relative_path", "artifact_type", "bytes", "sha256", "required_utf8_substrings"}, "expected.result_current_index") result_row = FormalRow( _need_string(result_expected["member_id"], "expected.result_current_index.member_id"), _safe_relative(result_expected["formal_relative_path"], "expected.result_current_index.formal_relative_path"), _need_string(result_expected["artifact_type"], "expected.result_current_index.artifact_type"), _need_int(result_expected["bytes"], "expected.result_current_index.bytes", positive=True), _need_sha(result_expected["sha256"], "expected.result_current_index.sha256"), ) result_formal = os.path.relpath(paths["result_current_index_path"], operation_root).replace("\\", "/") if result_row.formal_relative_path.casefold() != result_formal.casefold(): raise PublisherError("RESULT_INDEX_FORMAL_PATH", result_row.formal_relative_path) _verify_identity(paths["result_current_index_path"], result_row.bytes, result_row.sha256, "RESULT_INDEX_IDENTITY") required_result = result_expected["required_utf8_substrings"] if not isinstance(required_result, list) or not required_result: raise PublisherError("CONFIG_TYPE", "expected.result_current_index.required_utf8_substrings") result_text = _read_bytes(paths["result_current_index_path"]).decode("utf-8") for needle in required_result: if _need_string(needle, "expected.result_current_index.required_utf8_substrings") not in result_text: raise PublisherError("RESULT_INDEX_LINK", needle) current_expected_set = {_artifact_formal_tuple(row) for row in candidate_rows if row is not manifest_row} | {_formal_tuple(result_row)} current_actual_rows = _manifest_rows(current_manifest_data, candidate=False) current_actual_set = {_manifest_tuple(row) for row in current_actual_rows} if current_actual_set != current_expected_set or len(current_actual_rows) != len(current_expected_set): raise PublisherError("CURRENT_MANIFEST_COVERAGE", f"actual={len(current_actual_set)};expected={len(current_expected_set)}") candidate_set = _release_set(current_manifest_data, self_formal) if candidate_set != identity["candidate_release_set_sha256"]: raise PublisherError("CANDIDATE_RELEASE_SET", candidate_set) link_checks = _parse_checks(candidate["link_checks"], "expected.candidate.link_checks") evidence_checks = _parse_checks(candidate["evidence_checks"], "expected.candidate.evidence_checks") _verify_checks(paths["candidate_root"], link_checks, "LINK_CHECK_MISSING") _verify_checks(paths["candidate_root"], evidence_checks, "EVIDENCE_CHECK_MISSING") prior = expected["prior"] if not isinstance(prior, dict): raise PublisherError("CONFIG_TYPE", "expected.prior") prior_rows = _parse_formal_rows(prior.get("rows"), "expected.prior.rows") prior_paths = {row.member_id: _inside(operation_root, row.formal_relative_path) for row in prior_rows} for member, path in prior_paths.items(): _validate_parent_chain(operation_root, path, final_kind="file") _ordinary_file(path) required_prior_paths = {_norm(paths["case_current_index_path"]), _norm(paths["result_current_index_path"])} if not required_prior_paths.issubset({_norm(path) for path in prior_paths.values()}): raise PublisherError("PRIOR_ENTRY_COVERAGE", "cases/result current entries required") protected = { "candidate_root": paths["candidate_root"], "release_store_root": paths["release_store_root"], "target_release": paths["target_release"], "staging": paths["staging"], "attempt_receipt_root": paths["attempt_receipt_root"], "history_root": paths["history_root"], "ledger_path": paths["ledger_path"], "lock_path": paths["lock_path"], "config_path": config_path, } prior_items = list(prior_paths.items()) for index, (member, path) in enumerate(prior_items): for other_member, other_path in prior_items[index + 1:]: if _overlap(path, other_path): raise PublisherError("PRIOR_PATH_OVERLAP", f"{member}<->{other_member}") if _norm(path) not in required_prior_paths: for protected_name, protected_path in protected.items(): if _overlap(path, protected_path): raise PublisherError("PRIOR_PATH_OVERLAP", f"{member}<->{protected_name}") prior_manifest_path = _inside(operation_root, _safe_relative(prior["manifest_formal_relative_path"], "expected.prior.manifest_formal_relative_path")) _validate_parent_chain(operation_root, prior_manifest_path, final_kind="file") for protected_name, protected_path in protected.items(): if _overlap(prior_manifest_path, protected_path): raise PublisherError("PRIOR_MANIFEST_PATH_OVERLAP", protected_name) if any(_overlap(prior_manifest_path, path) for path in prior_paths.values()): raise PublisherError("PRIOR_MANIFEST_PATH_OVERLAP", "prior row") _, prior_release_set = _verify_prior_manifest(operation_root, prior, prior_rows) if prior["release_id"] != identity["prior_release_id"]: raise PublisherError("PRIOR_RELEASE_ID", str(prior["release_id"])) case_expected = expected["case_current_index"] if not isinstance(case_expected, dict): raise PublisherError("CONFIG_TYPE", "expected.case_current_index") _expect_keys(case_expected, {"bytes", "sha256", "required_utf8_substrings"}, "expected.case_current_index") prior_index_id = (_need_int(case_expected["bytes"], "expected.case_current_index.bytes", positive=True), _need_sha(case_expected["sha256"], "expected.case_current_index.sha256")) required_case = case_expected["required_utf8_substrings"] if not isinstance(required_case, list) or not required_case: raise PublisherError("CONFIG_TYPE", "expected.case_current_index.required_utf8_substrings") prior_index_data: bytes current_actual_id = _identity(paths["case_current_index_path"]) candidate_index_id = (candidate_index.bytes, candidate_index.sha256) receipt_exists = _exists(paths["attempt_receipt_root"]) target_exists = _exists(paths["target_release"]) if current_actual_id == prior_index_id and not receipt_exists and not target_exists: lifecycle = "FRESH" prior_index_data = _read_bytes(paths["case_current_index_path"]) for row in prior_rows: _verify_identity(_inside(operation_root, row.formal_relative_path), row.bytes, row.sha256, "PRIOR_IDENTITY") elif current_actual_id == candidate_index_id and receipt_exists and target_exists: lifecycle = "REPLAY" snapshot_index = _inside(paths["snapshot"], case_formal) _verify_identity(snapshot_index, *prior_index_id, "PRIOR_SNAPSHOT_INDEX") prior_index_data = _read_bytes(snapshot_index) elif current_actual_id == prior_index_id and receipt_exists: lifecycle = "TERMINAL_PRIOR" prior_index_data = _read_bytes(paths["case_current_index_path"]) else: raise PublisherError("CURRENT_INDEX_STATE", f"current={current_actual_id};receipt={receipt_exists};target={target_exists}") try: prior_text = prior_index_data.decode("utf-8") except UnicodeDecodeError as exc: raise PublisherError("CASE_INDEX_UTF8", "prior") from exc for needle in required_case: if _need_string(needle, "expected.case_current_index.required_utf8_substrings") not in prior_text: raise PublisherError("CASE_INDEX_LINK", needle) history = expected["history"] if not isinstance(history, dict): raise PublisherError("CONFIG_TYPE", "expected.history") _expect_keys(history, {"rows", "minimum_long_paths", "long_path_threshold"}, "expected.history") history_rows = _parse_history_rows(history["rows"], "expected.history.rows") threshold = _need_int(history["long_path_threshold"], "expected.history.long_path_threshold", positive=True) minimum = _need_int(history["minimum_long_paths"], "expected.history.minimum_long_paths") _verify_history(paths["history_root"], history_rows, threshold, minimum) state_expected = expected["current_state"] if not isinstance(state_expected, dict): raise PublisherError("CONFIG_TYPE", "expected.current_state") _expect_keys(state_expected, {"bytes", "sha256", "semantic_field", "semantic_value", "status_field", "status_value", "exit_code_field", "exit_code_value"}, "expected.current_state") state_id = (_need_int(state_expected["bytes"], "expected.current_state.bytes", positive=True), _need_sha(state_expected["sha256"], "expected.current_state.sha256")) _verify_identity(paths["current_state_path"], *state_id, "CURRENT_STATE_IDENTITY") try: state_value = json.loads(_read_bytes(paths["current_state_path"]).decode("utf-8")) except Exception as exc: raise PublisherError("CURRENT_STATE_PARSE", str(exc)) from exc for field_key, value_key in (("semantic_field", "semantic_value"), ("status_field", "status_value"), ("exit_code_field", "exit_code_value")): field = _need_string(state_expected[field_key], f"expected.current_state.{field_key}") if state_value.get(field) != state_expected[value_key]: raise PublisherError("CURRENT_STATE_SEMANTIC", field) ledger_expected = expected["ledger"] if not isinstance(ledger_expected, dict): raise PublisherError("CONFIG_TYPE", "expected.ledger") _expect_keys(ledger_expected, {"bytes", "sha256", "next_event_seq", "next_attempt_seq", "prior_attempt_id", "prior_terminal_state"}, "expected.ledger") base_size = _need_int(ledger_expected["bytes"], "expected.ledger.bytes", positive=True) base_sha = _need_sha(ledger_expected["sha256"], "expected.ledger.sha256") next_event = _need_int(ledger_expected["next_event_seq"], "expected.ledger.next_event_seq", positive=True) next_attempt = _need_int(ledger_expected["next_attempt_seq"], "expected.ledger.next_attempt_seq", positive=True) prior_attempt = _need_string(ledger_expected["prior_attempt_id"], "expected.ledger.prior_attempt_id") prior_terminal = _need_string(ledger_expected["prior_terminal_state"], "expected.ledger.prior_terminal_state") ledger_actual = _read_bytes(paths["ledger_path"]) if lifecycle == "FRESH": if (len(ledger_actual), _sha_bytes(ledger_actual)) != (base_size, base_sha): raise PublisherError("LEDGER_IDENTITY", str(paths["ledger_path"])) ledger_base = ledger_actual else: if len(ledger_actual) < base_size: raise PublisherError("LEDGER_BASE_PREFIX", "short") ledger_base = ledger_actual[:base_size] if _sha_bytes(ledger_base) != base_sha: raise PublisherError("LEDGER_BASE_PREFIX", "hash") base_rows = _read_ledger(ledger_base) derived_event, derived_attempt = _derive_sequences(base_rows, identity) if derived_event != next_event: raise PublisherError("LEDGER_NEXT_EVENT", f"{derived_event}!={next_event}") if derived_attempt != next_attempt: raise PublisherError("LEDGER_NEXT_ATTEMPT", f"{derived_attempt}!={next_attempt}") prior_matches = [row for row in base_rows if row["attempt_id"] == prior_attempt] if len(prior_matches) == 0 or prior_matches[-1]["state"] != prior_terminal: raise PublisherError("LEDGER_PRIOR_TERMINAL", prior_attempt) test_control = config["test_control"] _expect_keys(test_control, {"environment", "fault", "race_marker_relative_path"}, "test_control") environment = _need_string(test_control["environment"], "test_control.environment") fault = _need_string(test_control["fault"], "test_control.fault") marker = test_control["race_marker_relative_path"] if not isinstance(marker, str): raise PublisherError("CONFIG_TYPE", "test_control.race_marker_relative_path") allowed_faults = {"NONE", "POSTCOMMIT_READBACK_FAIL", "EXTRA_TARGET_AFTER_RENAME", "PAUSE_AFTER_LOCK"} if environment == "PRODUCTION" and (fault != "NONE" or marker): raise PublisherError("TEST_CONTROL_PRODUCTION", fault) if environment not in ("PRODUCTION", "ISOLATED_TEST") or fault not in allowed_faults: raise PublisherError("CONFIG_ENUM", "test_control") if fault == "PAUSE_AFTER_LOCK" and not marker: raise PublisherError("CONFIG_TYPE", "race marker required") if marker: paths["race_marker"] = _inside(operation_root, _safe_relative(marker, "test_control.race_marker_relative_path")) return Plan( config=config, config_path=config_path, config_data=config_data, config_sha256=_sha_bytes(config_data), operation_root=operation_root, identity=identity, paths=paths, candidate_rows=candidate_rows, prior_rows=prior_rows, history_rows=history_rows, link_checks=link_checks, evidence_checks=evidence_checks, ledger_base_data=ledger_base, next_event_seq=next_event, next_attempt_seq=next_attempt, prior_index_data=prior_index_data, candidate_index_data=_read_bytes(_inside(paths["candidate_root"], candidate_index.relative_path)), target_release_relative=target_rel, target_rows=target_rows, manifest_row=manifest_row, result_row=result_row, prior_release_set=prior_release_set, lifecycle=lifecycle, ) def _copy_file(source: Path, target: Path) -> None: os.makedirs(_long(target.parent), exist_ok=True) _ordinary_dir(target.parent) if _exists(target): raise PublisherError("TARGET_EXISTS", str(target), exit_code=20) data = _read_bytes(source) flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL | getattr(os, "O_BINARY", 0) fd = os.open(_long(target), flags, 0o600) try: offset = 0 while offset < len(data): offset += os.write(fd, data[offset:]) os.fsync(fd) finally: os.close(fd) if _identity(target) != (len(data), _sha_bytes(data)): raise PublisherError("COPY_READBACK", str(target), exit_code=20) def _create_exclusive(path: Path, data: bytes) -> None: if not _exists(path.parent): os.makedirs(_long(path.parent), exist_ok=False) _ordinary_dir(path.parent) flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL | getattr(os, "O_BINARY", 0) try: fd = os.open(_long(path), flags, 0o600) except FileExistsError as exc: raise PublisherError("TARGET_EXISTS", str(path), exit_code=20) from exc try: offset = 0 while offset < len(data): offset += os.write(fd, data[offset:]) os.fsync(fd) finally: os.close(fd) def _atomic_replace(path: Path, data: bytes, attempt: str) -> None: temp = path.with_name(f".{path.name}.{attempt}.tmp") if _exists(temp): raise PublisherError("TEMP_EXISTS", str(temp), exit_code=20) _create_exclusive(temp, data) try: os.replace(_long(temp), _long(path)) except Exception: if _exists(temp): os.unlink(_long(temp)) raise def _target_relative(plan: Plan, row: ArtifactRow) -> str: prefix = plan.target_release_relative.rstrip("/") + "/" return row.formal_relative_path[len(prefix):] def _verify_target(plan: Plan) -> None: expected = {_target_relative(plan, row) for row in plan.target_rows} actual = set(_walk_files(plan.paths["target_release"])) if actual != expected: raise PublisherError("TARGET_EXACT_SET", f"missing={sorted(expected-actual)};extra={sorted(actual-expected)}", exit_code=20) for row in plan.target_rows: _verify_identity(_inside(plan.paths["target_release"], _target_relative(plan, row)), row.bytes, row.sha256, "TARGET_IDENTITY") manifest_path = _inside(plan.paths["target_release"], _target_relative(plan, plan.manifest_row)) data = _read_bytes(manifest_path) expected_set = {_artifact_formal_tuple(row) for row in plan.candidate_rows if row is not plan.manifest_row} | {_formal_tuple(plan.result_row)} actual_rows = _manifest_rows(data, candidate=False) actual_set = {_manifest_tuple(row) for row in actual_rows} if actual_set != expected_set or len(actual_rows) != len(expected_set): raise PublisherError("TARGET_MANIFEST_COVERAGE", f"actual={len(actual_set)};expected={len(expected_set)}", exit_code=20) if _release_set(data, plan.manifest_row.formal_relative_path) != plan.identity["candidate_release_set_sha256"]: raise PublisherError("TARGET_RELEASE_SET", "mismatch", exit_code=20) def _event_line(plan: Plan, sequence: int, state: str, receipt: str, process_identity: str, event_time: str) -> bytes: row = [ plan.identity["release_id"], str(sequence), state, plan.identity["prior_release_id"], plan.prior_release_set, plan.identity["candidate_release_set_sha256"], plan.identity["task_id"], plan.identity["case_id"], plan.identity["batch_id"], plan.identity["run_id"], plan.identity["canonical_audit_id"], plan.identity["operator"], process_identity, event_time, receipt, plan.identity["attempt_id"], str(plan.next_attempt_seq), ] stream = io.StringIO(newline="") csv.writer(stream, lineterminator="\n").writerow(row) return stream.getvalue().encode("utf-8") def _append_event(plan: Plan, state: str, offset: int, receipt: str, process_identity: str) -> None: rows = _read_ledger(_read_bytes(plan.paths["ledger_path"])) attempt_rows = _event_rows_for_attempt(rows, plan.identity["attempt_id"]) current = datetime.now(timezone.utc) if attempt_rows: previous = _parse_strict_utc(attempt_rows[-1]["event_time"], "EVENT_TIME_EXISTING") if current <= previous: current = previous + timedelta(microseconds=1) event_time = current.isoformat(timespec="microseconds").replace("+00:00", "Z") with open(_long(plan.paths["ledger_path"]), "ab", buffering=0) as handle: handle.write(_event_line(plan, plan.next_event_seq + offset, state, receipt, process_identity, event_time)) os.fsync(handle.fileno()) def _process_identity() -> str: return f"PID-{os.getpid()}-{uuid.uuid4().hex.upper()}" def _receipt_relative(plan: Plan, name: str) -> str: return os.path.relpath(plan.paths["attempt_receipt_root"] / name, plan.operation_root).replace("\\", "/") def _locked_revalidate(plan: Plan) -> None: if _read_bytes(plan.config_path) != plan.config_data: raise PublisherError("CONFIG_IDENTITY_LOCKED", "changed after preflight") _physical_chain(plan.operation_root, final_kind="dir") if _volume(plan.operation_root).upper() != plan.config["roots"]["volume_identity"].upper(): raise PublisherError("VOLUME_IDENTITY_LOCKED", "changed after preflight") ledger = _read_bytes(plan.paths["ledger_path"]) if ledger != plan.ledger_base_data: raise PublisherError("LEDGER_IDENTITY_LOCKED", "changed after preflight") rows = _read_ledger(ledger) if _derive_sequences(rows, plan.identity) != (plan.next_event_seq, plan.next_attempt_seq): raise PublisherError("LEDGER_SEQUENCE_LOCKED", "rederived sequence mismatch") if _read_bytes(plan.paths["case_current_index_path"]) != plan.prior_index_data: raise PublisherError("CURRENT_INDEX_LOCKED", "changed after preflight") _verify_identity(plan.paths["result_current_index_path"], plan.result_row.bytes, plan.result_row.sha256, "RESULT_INDEX_LOCKED") for row in plan.prior_rows: _verify_identity(_inside(plan.operation_root, row.formal_relative_path), row.bytes, row.sha256, "PRIOR_LOCKED") prior = plan.config["expected"]["prior"] prior_manifest = _inside(plan.operation_root, prior["manifest_formal_relative_path"]) _verify_identity(prior_manifest, prior["manifest_bytes"], prior["manifest_sha256"], "PRIOR_MANIFEST_LOCKED") if _release_set(_read_bytes(prior_manifest), prior["manifest_self_formal_relative_path"]) != plan.prior_release_set: raise PublisherError("PRIOR_RELEASE_SET_LOCKED", "mismatch") _verify_history(plan.paths["history_root"], plan.history_rows, plan.config["expected"]["history"]["long_path_threshold"], plan.config["expected"]["history"]["minimum_long_paths"]) for row in plan.candidate_rows: _verify_identity(_inside(plan.paths["candidate_root"], row.relative_path), row.bytes, row.sha256, "CANDIDATE_LOCKED") candidate = plan.config["expected"]["candidate"] candidate_manifest = _inside(plan.paths["candidate_root"], candidate["manifest_relative_path"]) _verify_identity(candidate_manifest, candidate["manifest_bytes"], candidate["manifest_sha256"], "CANDIDATE_MANIFEST_LOCKED") expected_candidate = {candidate["manifest_relative_path"]} | {row.relative_path for row in plan.candidate_rows} actual_candidate = set(_walk_files(plan.paths["candidate_root"])) if actual_candidate != expected_candidate: raise PublisherError("CANDIDATE_EXACT_SET_LOCKED", f"missing={sorted(expected_candidate-actual_candidate)};extra={sorted(actual_candidate-expected_candidate)}") _verify_checks(plan.paths["candidate_root"], plan.link_checks, "LINK_CHECK_LOCKED") _verify_checks(plan.paths["candidate_root"], plan.evidence_checks, "EVIDENCE_CHECK_LOCKED") if _exists(plan.paths["target_release"]) or _exists(plan.paths["staging"]) or _exists(plan.paths["attempt_receipt_root"]): raise PublisherError("TARGET_APPEARED_LOCKED", "target/staging/receipt") def _snapshot_prior(plan: Plan) -> None: for row in plan.prior_rows: source = _inside(plan.operation_root, row.formal_relative_path) target = _inside(plan.paths["snapshot"], row.formal_relative_path) _copy_file(source, target) manifest_rel = plan.config["expected"]["prior"]["manifest_formal_relative_path"] _copy_file(_inside(plan.operation_root, manifest_rel), _inside(plan.paths["snapshot"], manifest_rel)) expected = {row.formal_relative_path for row in plan.prior_rows} | {manifest_rel} actual = set(_walk_files(plan.paths["snapshot"])) if actual != expected: raise PublisherError("SNAPSHOT_EXACT_SET", f"missing={sorted(expected-actual)};extra={sorted(actual-expected)}") def _verify_snapshot(plan: Plan) -> None: manifest_rel = plan.config["expected"]["prior"]["manifest_formal_relative_path"] expected = {row.formal_relative_path for row in plan.prior_rows} | {manifest_rel} actual = set(_walk_files(plan.paths["snapshot"])) if actual != expected: raise PublisherError("REPLAY_SNAPSHOT_EXACT_SET", f"missing={sorted(expected-actual)};extra={sorted(actual-expected)}") for row in plan.prior_rows: _verify_identity(_inside(plan.paths["snapshot"], row.formal_relative_path), row.bytes, row.sha256, "REPLAY_SNAPSHOT_IDENTITY") prior = plan.config["expected"]["prior"] manifest_path = _inside(plan.paths["snapshot"], manifest_rel) _verify_identity(manifest_path, prior["manifest_bytes"], prior["manifest_sha256"], "REPLAY_SNAPSHOT_MANIFEST") if _release_set(_read_bytes(manifest_path), prior["manifest_self_formal_relative_path"]) != plan.prior_release_set: raise PublisherError("REPLAY_SNAPSHOT_RELEASE_SET", "mismatch") def _terminal( plan: Plan, status: str, exit_code: int, states: tuple[str, ...], process_identity: str, event_chain_sha256: str, event_time_start_utc: str, event_time_end_utc: str, event_process_identities: tuple[str, ...], *, committed: bool, rolled_back: bool, ) -> dict[str, Any]: target_set = _sha_bytes(_canonical_json([ {"bytes": row.bytes, "formal_relative_path": row.formal_relative_path, "sha256": row.sha256} for row in sorted(plan.target_rows, key=lambda item: item.formal_relative_path.casefold()) ], newline=False)) return { "schema_version": TERMINAL_SCHEMA, "status": status, "exit_code": exit_code, "task_id": plan.identity["task_id"], "case_id": plan.identity["case_id"], "batch_id": plan.identity["batch_id"], "run_id": plan.identity["run_id"], "attempt_id": plan.identity["attempt_id"], "release_id": plan.identity["release_id"], "prior_release_id": plan.identity["prior_release_id"], "canonical_audit_id": plan.identity["canonical_audit_id"], "review_handoff_id": plan.identity["review_handoff_id"], "config_path": os.path.relpath(plan.config_path, plan.operation_root).replace("\\", "/"), "config_bytes": len(plan.config_data), "config_sha256": plan.config_sha256, "resolved_root": os.path.abspath(plan.operation_root), "volume_identity": _volume(plan.operation_root).upper(), "commit_strategy": COMMIT_STRATEGY, "case_current_prior_bytes": len(plan.prior_index_data), "case_current_prior_sha256": _sha_bytes(plan.prior_index_data), "case_current_candidate_bytes": len(plan.candidate_index_data), "case_current_candidate_sha256": _sha_bytes(plan.candidate_index_data), "result_current_bytes": plan.result_row.bytes, "result_current_sha256": plan.result_row.sha256, "prior_release_set_sha256": plan.prior_release_set, "candidate_release_set_sha256": plan.identity["candidate_release_set_sha256"], "target_release_relative_path": plan.target_release_relative, "target_set_sha256": target_set, "event_seq_start": plan.next_event_seq, "event_seq_end": plan.next_event_seq + len(states) - 1, "event_states": list(states), "attempt_event_chain_schema": EVENT_CHAIN_SCHEMA, "attempt_event_chain_row_count": len(states), "attempt_event_chain_sha256": event_chain_sha256, "event_time_start_utc": event_time_start_utc, "event_time_end_utc": event_time_end_utc, "event_process_identities": list(event_process_identities), "attempt_seq": plan.next_attempt_seq, "process_instance_identity": process_identity, "committed": committed, "rolled_back": rolled_back, "lock_absent_on_return": True, } def _write_terminal(plan: Plan, value: dict[str, Any]) -> None: _create_exclusive(plan.paths["attempt_receipt_root"] / "terminal.json", _canonical_json(value)) def _expected_event_receipt(plan: Plan, state: str, rollback_terminal_name: str) -> str: if state in ("PREPARED", "VERIFIED"): return _receipt_relative(plan, "prior_snapshot.json") if state in ("COMMITTING", "COMMITTED"): return _receipt_relative(plan, "terminal.json") if state in ("ROLLING_BACK", "ROLLED_BACK"): return _receipt_relative(plan, rollback_terminal_name) raise PublisherError("EVENT_STATE_UNSUPPORTED", state, exit_code=27) def _validate_attempt_event_chain( plan: Plan, expected_states: tuple[str, ...], process_identities: tuple[str, ...], *, rollback_terminal_name: str = "terminal.json", expected_digest: str | None = None, expected_time_start: str | None = None, expected_time_end: str | None = None, ) -> tuple[str, str, str]: if len(process_identities) != len(expected_states) or any( not isinstance(value, str) or not value.startswith("PID-") for value in process_identities ): raise PublisherError("EVENT_PROCESS_IDENTITIES", "invalid", exit_code=27) rows = _read_ledger(_read_bytes(plan.paths["ledger_path"])) base_count = len(_read_ledger(plan.ledger_base_data)) attempt_rows = rows[base_count:] if len(attempt_rows) != len(expected_states): raise PublisherError("EVENT_CHAIN_ROW_COUNT", f"{len(attempt_rows)}!={len(expected_states)}", exit_code=27) expected_sequences = list(range(plan.next_event_seq, plan.next_event_seq + len(expected_states))) previous_time: datetime | None = None event_times: list[str] = [] for index, (row, state, sequence, process_identity) in enumerate( zip(attempt_rows, expected_states, expected_sequences, process_identities, strict=True) ): expected = { "release_id": plan.identity["release_id"], "event_seq": str(sequence), "state": state, "prior_release_id": plan.identity["prior_release_id"], "prior_release_set_sha256": plan.prior_release_set, "candidate_release_set_sha256": plan.identity["candidate_release_set_sha256"], "task_id": plan.identity["task_id"], "case_id": plan.identity["case_id"], "batch_id": plan.identity["batch_id"], "run_id": plan.identity["run_id"], "accepted_audit_id": plan.identity["canonical_audit_id"], "operator": plan.identity["operator"], "process_identity": process_identity, "recovery_or_rollback_receipt": _expected_event_receipt(plan, state, rollback_terminal_name), "attempt_id": plan.identity["attempt_id"], "attempt_seq": str(plan.next_attempt_seq), } for column, value in expected.items(): if row[column] != value: raise PublisherError("EVENT_CHAIN_FIELD_BINDING", f"row={index};state={state};field={column}", exit_code=27) parsed_time = _parse_strict_utc(row["event_time"], "EVENT_TIME_UTC") if previous_time is not None and parsed_time <= previous_time: raise PublisherError("EVENT_TIME_ORDER", f"row={index};state={state}", exit_code=27) previous_time = parsed_time event_times.append(row["event_time"]) digest = _event_chain_digest(attempt_rows) if expected_digest is not None and digest != _need_sha(expected_digest, "terminal.attempt_event_chain_sha256"): raise PublisherError("EVENT_CHAIN_DIGEST", "mismatch", exit_code=27) if expected_time_start is not None and event_times[0] != expected_time_start: raise PublisherError("EVENT_TIME_START_BINDING", "mismatch", exit_code=27) if expected_time_end is not None and event_times[-1] != expected_time_end: raise PublisherError("EVENT_TIME_END_BINDING", "mismatch", exit_code=27) return digest, event_times[0], event_times[-1] def _validate_event_chain(plan: Plan, terminal: dict[str, Any]) -> None: expected_states = tuple(terminal["event_states"]) process_identities = terminal.get("event_process_identities") if not isinstance(process_identities, list): raise PublisherError("REPLAY_EVENT_PROCESS_IDENTITIES", "invalid") digest, start_time, end_time = _validate_attempt_event_chain( plan, expected_states, tuple(process_identities), expected_digest=terminal["attempt_event_chain_sha256"], expected_time_start=terminal["event_time_start_utc"], expected_time_end=terminal["event_time_end_utc"], ) if terminal["attempt_event_chain_schema"] != EVENT_CHAIN_SCHEMA: raise PublisherError("REPLAY_EVENT_CHAIN_SCHEMA", str(terminal["attempt_event_chain_schema"])) if terminal["attempt_event_chain_row_count"] != len(expected_states): raise PublisherError("REPLAY_EVENT_CHAIN_COUNT", str(terminal["attempt_event_chain_row_count"])) if terminal["event_seq_end"] != plan.next_event_seq + len(expected_states) - 1 or terminal["event_seq_start"] != plan.next_event_seq: raise PublisherError("REPLAY_TERMINAL_EVENT_RANGE", "mismatch") if (digest, start_time, end_time) != ( terminal["attempt_event_chain_sha256"], terminal["event_time_start_utc"], terminal["event_time_end_utc"] ): raise PublisherError("REPLAY_EVENT_EVIDENCE", "mismatch") def _verify_terminal_binding(plan: Plan, terminal: dict[str, Any]) -> None: process_identity = terminal.get("process_instance_identity") if not isinstance(process_identity, str) or not process_identity.startswith("PID-"): raise PublisherError("REPLAY_TERMINAL_PROCESS", "invalid") chain_digest = terminal.get("attempt_event_chain_sha256") start_time = terminal.get("event_time_start_utc") end_time = terminal.get("event_time_end_utc") if not isinstance(chain_digest, str) or not isinstance(start_time, str) or not isinstance(end_time, str): raise PublisherError("REPLAY_TERMINAL_EVENT_EVIDENCE", "invalid") expected = _terminal( plan, "COMMITTED", 0, SUCCESS_STATES, process_identity, _need_sha(chain_digest, "terminal.attempt_event_chain_sha256"), start_time, end_time, (process_identity,) * len(SUCCESS_STATES), committed=True, rolled_back=False, ) if set(terminal) != set(expected): raise PublisherError("REPLAY_TERMINAL_KEYS", f"missing={sorted(set(expected)-set(terminal))};extra={sorted(set(terminal)-set(expected))}") for key, value in expected.items(): if terminal.get(key) != value: raise PublisherError("REPLAY_TERMINAL_BINDING", key) if _exists(plan.paths["lock_path"]): raise PublisherError("REPLAY_LOCK_PRESENT", str(plan.paths["lock_path"])) def _verify_replay(plan: Plan) -> dict[str, Any]: if plan.lifecycle != "REPLAY": raise PublisherError("REPLAY_LIFECYCLE", plan.lifecycle) if _read_bytes(plan.paths["case_current_index_path"]) != plan.candidate_index_data: raise PublisherError("REPLAY_CURRENT_INDEX", "not candidate") _verify_identity(plan.paths["result_current_index_path"], plan.result_row.bytes, plan.result_row.sha256, "REPLAY_RESULT_INDEX") _verify_target(plan) _verify_snapshot(plan) terminal_path = plan.paths["attempt_receipt_root"] / "terminal.json" try: terminal = json.loads(_read_bytes(terminal_path).decode("utf-8"), object_pairs_hook=_pairs_no_duplicates) except PublisherError: raise except Exception as exc: raise PublisherError("REPLAY_TERMINAL_PARSE", str(exc)) from exc if not isinstance(terminal, dict): raise PublisherError("REPLAY_TERMINAL_TYPE", "not object") _verify_terminal_binding(plan, terminal) _validate_event_chain(plan, terminal) expected_receipt = { "prior_snapshot.json", "terminal.json", *{f"prior_snapshot/{row.formal_relative_path}" for row in plan.prior_rows}, f"prior_snapshot/{plan.config['expected']['prior']['manifest_formal_relative_path']}", } actual_receipt = set(_walk_files(plan.paths["attempt_receipt_root"])) if actual_receipt != expected_receipt: raise PublisherError("REPLAY_RECEIPT_EXACT_SET", f"missing={sorted(expected_receipt-actual_receipt)};extra={sorted(actual_receipt-expected_receipt)}") value = dict(terminal) value["status"] = "IDEMPOTENT_COMMITTED" return value def _rollback( plan: Plan, process_identity: str, offset: int, detail: str, base_states: tuple[str, ...], terminal_name: str, *, base_process_identity: str | None = None, ) -> dict[str, Any]: _append_event(plan, "ROLLING_BACK", offset, _receipt_relative(plan, terminal_name), process_identity) _atomic_replace(plan.paths["case_current_index_path"], plan.prior_index_data, plan.identity["attempt_id"] + "-rollback") if _read_bytes(plan.paths["case_current_index_path"]) != plan.prior_index_data: raise PublisherError("ROLLBACK_READBACK", detail, exit_code=27) _append_event(plan, "ROLLED_BACK", offset + 1, _receipt_relative(plan, terminal_name), process_identity) states = base_states + ("ROLLING_BACK", "ROLLED_BACK") base_process = base_process_identity or process_identity event_processes = (base_process,) * len(base_states) + (process_identity, process_identity) chain_digest, start_time, end_time = _validate_attempt_event_chain( plan, states, event_processes, rollback_terminal_name=terminal_name ) value = _terminal( plan, "ROLLED_BACK", 20, states, process_identity, chain_digest, start_time, end_time, event_processes, committed=False, rolled_back=True, ) value["failure_detail"] = detail _create_exclusive(plan.paths["attempt_receipt_root"] / terminal_name, _canonical_json(value)) return value def _recover_invalid_replay(plan: Plan, reason: PublisherError) -> dict[str, Any]: lock_value = { "schema_version": TERMINAL_SCHEMA, "attempt_id": plan.identity["attempt_id"], "config_bytes": len(plan.config_data), "config_sha256": plan.config_sha256, "process_instance_identity": _process_identity(), "acquired_at": _utc_now(), } _create_exclusive(plan.paths["lock_path"], _canonical_json(lock_value)) process_identity = lock_value["process_instance_identity"] try: if _read_bytes(plan.paths["case_current_index_path"]) != plan.candidate_index_data: raise PublisherError("RECOVERY_CURRENT_CHANGED", "not candidate", exit_code=27) _verify_snapshot(plan) ledger_rows = _read_ledger(_read_bytes(plan.paths["ledger_path"])) attempt_rows = _event_rows_for_attempt(ledger_rows, plan.identity["attempt_id"]) process_values = {row["process_identity"] for row in attempt_rows} if len(process_values) != 1: raise PublisherError("RECOVERY_EVENT_PROCESS_UNKNOWN", str(sorted(process_values)), exit_code=27) process_anchor = next(iter(process_values)) digest_anchor: str | None = None start_anchor: str | None = None end_anchor: str | None = None try: terminal = json.loads( _read_bytes(plan.paths["attempt_receipt_root"] / "terminal.json").decode("utf-8"), object_pairs_hook=_pairs_no_duplicates, ) if isinstance(terminal, dict): if isinstance(terminal.get("process_instance_identity"), str): process_anchor = terminal["process_instance_identity"] if isinstance(terminal.get("attempt_event_chain_sha256"), str): digest_anchor = terminal["attempt_event_chain_sha256"] if isinstance(terminal.get("event_time_start_utc"), str): start_anchor = terminal["event_time_start_utc"] if isinstance(terminal.get("event_time_end_utc"), str): end_anchor = terminal["event_time_end_utc"] except Exception: # A malformed terminal can still be recovered only when the complete # ledger chain independently validates against the declarative plan. pass _validate_attempt_event_chain( plan, SUCCESS_STATES, (process_anchor,) * len(SUCCESS_STATES), expected_digest=digest_anchor, expected_time_start=start_anchor, expected_time_end=end_anchor, ) value = _rollback( plan, process_identity, len(SUCCESS_STATES), f"REPLAY_INVALID:{reason.code}:{reason.detail}", SUCCESS_STATES, "recovery_terminal.json", base_process_identity=process_anchor, ) return value finally: if _exists(plan.paths["lock_path"]): os.unlink(_long(plan.paths["lock_path"])) def _publish(plan: Plan) -> dict[str, Any]: if plan.lifecycle == "TERMINAL_PRIOR": raise PublisherError("TERMINAL_REPEAT_BLOCKED", str(plan.paths["attempt_receipt_root"])) if plan.lifecycle != "FRESH": raise PublisherError("PUBLISH_LIFECYCLE", plan.lifecycle) process_identity = _process_identity() lock_value = { "schema_version": TERMINAL_SCHEMA, "attempt_id": plan.identity["attempt_id"], "config_path": os.path.relpath(plan.config_path, plan.operation_root).replace("\\", "/"), "config_bytes": len(plan.config_data), "config_sha256": plan.config_sha256, "resolved_root": os.path.abspath(plan.operation_root), "volume_identity": _volume(plan.operation_root).upper(), "process_instance_identity": process_identity, "acquired_at": _utc_now(), } _create_exclusive(plan.paths["lock_path"], _canonical_json(lock_value)) switched = False try: fault = plan.config["test_control"]["fault"] if fault == "PAUSE_AFTER_LOCK": marker = plan.paths["race_marker"] deadline = time.monotonic() + 5.0 while time.monotonic() < deadline and not _exists(marker): time.sleep(0.01) if not _exists(marker): raise PublisherError("TEST_RACE_MARKER_TIMEOUT", str(marker)) _locked_revalidate(plan) os.makedirs(_long(plan.paths["attempt_receipt_root"]), exist_ok=False) _ordinary_dir(plan.paths["attempt_receipt_root"]) _snapshot_prior(plan) snapshot_receipt = { "schema_version": TERMINAL_SCHEMA, "attempt_id": plan.identity["attempt_id"], "config_bytes": len(plan.config_data), "config_sha256": plan.config_sha256, "prior_release_set_sha256": plan.prior_release_set, "row_count": len(plan.prior_rows), "created_at": _utc_now(), } _create_exclusive(plan.paths["attempt_receipt_root"] / "prior_snapshot.json", _canonical_json(snapshot_receipt)) _append_event(plan, "PREPARED", 0, _receipt_relative(plan, "prior_snapshot.json"), process_identity) os.makedirs(_long(plan.paths["staging"]), exist_ok=False) for row in plan.target_rows: _copy_file(_inside(plan.paths["candidate_root"], row.relative_path), _inside(plan.paths["staging"], _target_relative(plan, row))) expected_stage = {_target_relative(plan, row) for row in plan.target_rows} if set(_walk_files(plan.paths["staging"])) != expected_stage: raise PublisherError("STAGING_EXACT_SET", "mismatch", exit_code=20) for row in plan.target_rows: _verify_identity(_inside(plan.paths["staging"], _target_relative(plan, row)), row.bytes, row.sha256, "STAGING_IDENTITY") _append_event(plan, "VERIFIED", 1, _receipt_relative(plan, "prior_snapshot.json"), process_identity) _append_event(plan, "COMMITTING", 2, _receipt_relative(plan, "terminal.json"), process_identity) os.rename(_long(plan.paths["staging"]), _long(plan.paths["target_release"])) if fault == "EXTRA_TARGET_AFTER_RENAME": _create_exclusive(plan.paths["target_release"] / "UNDECLARED.txt", b"attack\n") _atomic_replace(plan.paths["case_current_index_path"], plan.candidate_index_data, plan.identity["attempt_id"]) switched = True if fault == "POSTCOMMIT_READBACK_FAIL": raise PublisherError("INJECTED_POSTCOMMIT", "isolated test", exit_code=20) _verify_target(plan) if _read_bytes(plan.paths["case_current_index_path"]) != plan.candidate_index_data: raise PublisherError("POSTCOMMIT_CURRENT_INDEX", "mismatch", exit_code=20) _verify_identity(plan.paths["result_current_index_path"], plan.result_row.bytes, plan.result_row.sha256, "POSTCOMMIT_RESULT_INDEX") _append_event(plan, "COMMITTED", 3, _receipt_relative(plan, "terminal.json"), process_identity) event_processes = (process_identity,) * len(SUCCESS_STATES) chain_digest, start_time, end_time = _validate_attempt_event_chain(plan, SUCCESS_STATES, event_processes) value = _terminal( plan, "COMMITTED", 0, SUCCESS_STATES, process_identity, chain_digest, start_time, end_time, event_processes, committed=True, rolled_back=False, ) _write_terminal(plan, value) return value except PublisherError as exc: if switched: return _rollback(plan, process_identity, 3, f"{exc.code}:{exc.detail}", SUCCESS_STATES[:3], "terminal.json") raise finally: if _exists(plan.paths["lock_path"]): os.unlink(_long(plan.paths["lock_path"])) def run_config(config_path: Path, *, validate_only: bool = False) -> dict[str, Any]: config, config_data = _load_config(config_path) if ( config.get("schema_version") == DIRECT_CONFIG_SCHEMA and isinstance(config.get("commit"), dict) and config["commit"].get("strategy") == DIRECT_COMMIT_STRATEGY ): # The direct stable-path transaction is intentionally isolated from the # accepted release-directory strategy. Both use the same public CLI, # ledger and event-chain primitives, while retaining separate strict # schemas and topology validators. from .direct_stable_path import run_direct_config return run_direct_config( config, Path(os.path.abspath(config_path)), config_data, validate_only=validate_only, ) plan = _validate_config(config, Path(os.path.abspath(config_path)), config_data) if validate_only: return { "schema_version": TERMINAL_SCHEMA, "status": "VALIDATION_PASS", "exit_code": 0, "lifecycle": plan.lifecycle, "candidate_count": len(plan.candidate_rows), "target_count": len(plan.target_rows), "history_count": len(plan.history_rows), "next_event_seq": plan.next_event_seq, "next_attempt_seq": plan.next_attempt_seq, "config_bytes": len(plan.config_data), "config_sha256": plan.config_sha256, } if plan.lifecycle == "REPLAY": try: return _verify_replay(plan) except PublisherError as exc: return _recover_invalid_replay(plan, exc) return _publish(plan) def main(argv: list[str] | None = None) -> int: if hasattr(sys.stdout, "reconfigure"): sys.stdout.reconfigure(encoding="utf-8", errors="strict") parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--config", required=True, type=Path) parser.add_argument("--validate-only", action="store_true") parser.add_argument("--read-direct-current", action="store_true") args = parser.parse_args(argv) try: if args.validate_only and args.read_direct_current: raise PublisherError("CLI_MODE", "validate-only and read-direct-current are mutually exclusive") if args.read_direct_current: from .authoritative_reader import read_direct_current value = read_direct_current(args.config) else: value = run_config(args.config, validate_only=args.validate_only) print(json.dumps(value, ensure_ascii=False, separators=(",", ":"), sort_keys=True)) return int(value.get("exit_code", 0)) except PublisherError as exc: value = {"schema_version": TERMINAL_SCHEMA, "status": "FAIL_CLOSED", "exit_code": exc.exit_code, "error_code": exc.code, "detail": exc.detail} print(json.dumps(value, ensure_ascii=False, separators=(",", ":"), sort_keys=True)) return exc.exit_code except Exception as exc: # fail closed without inventing state value = {"schema_version": TERMINAL_SCHEMA, "status": "FAIL_CLOSED", "exit_code": 27, "error_code": "UNEXPECTED", "detail": f"{type(exc).__name__}:{exc}"} print(json.dumps(value, ensure_ascii=False, separators=(",", ":"), sort_keys=True)) return 27 if __name__ == "__main__": sys.exit(main())