#!/usr/bin/env python3 """Build a private, row-level replay receipt for one applied KB proposal. The guarded apply transaction keeps the immutable reviewed payload in ``kb_stage.kb_proposals``. This module binds that payload to the exact canonical rows observed after commit, including generated UUIDs and timestamps. The result is sufficient input for a future genesis-plus-ledger replayer without putting claim bodies or source excerpts in logs or stdout. """ from __future__ import annotations import hashlib import json import os import re import tempfile import uuid from datetime import datetime, timezone from pathlib import Path from typing import Any RECEIPT_CONTRACT_VERSION = 1 DEFAULT_RECEIPT_DIR = "/opt/teleo-eval/logs/kb-apply-receipts" UTC_SESSION_SQL = "set timezone = 'UTC';" _ISO_TIMESTAMP = re.compile(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,6})?(?:Z|[+-]\d{2}:\d{2})$") _UUID_FIELDS = { "id", "agent_id", "owner_agent_id", "created_by", "superseded_by", "supersedes_id", "accepted_by_proposal_id", "claim_id", "source_id", "accepted_from_proposal_id", "from_claim", "to_claim", "supersedes_assessment_id", "reviewed_by_agent_id", "applied_by_agent_id", } _TIMESTAMP_FIELDS = {"captured_at", "created_at", "updated_at", "reviewed_at", "applied_at"} def canonical_utc_timestamp(value: Any, *, path: str = "timestamp") -> str: """Normalize a typed timestamp to fixed-microsecond UTC receipt text.""" if not isinstance(value, str) or not _ISO_TIMESTAMP.fullmatch(value): raise ValueError(f"{path} must be a timezone-aware ISO-8601 timestamp with at most 6 fractional digits") try: parsed = datetime.fromisoformat(value.replace("Z", "+00:00")) except ValueError as exc: raise ValueError(f"{path} must be a valid ISO-8601 timestamp") from exc if parsed.tzinfo is None: raise ValueError(f"{path} must include a timezone") return parsed.astimezone(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%fZ") def _canonical_uuid(value: Any, *, path: str) -> str: try: return str(uuid.UUID(str(value))) except (AttributeError, TypeError, ValueError) as exc: raise ValueError(f"{path} must be a UUID") from exc def _normalize_typed_value(field: str, value: Any, *, path: str) -> Any: if value is None: return None if field in _UUID_FIELDS: return _canonical_uuid(value, path=path) if field in _TIMESTAMP_FIELDS: return canonical_utc_timestamp(value, path=path) return value def _normalize_typed_row(row: dict[str, Any], *, path: str) -> dict[str, Any]: return {field: _normalize_typed_value(field, value, path=f"{path}.{field}") for field, value in row.items()} def normalize_typed_value(field: str, value: Any, *, path: str) -> Any: """Canonicalize a value according to its PostgreSQL column type.""" return _normalize_typed_value(field, value, path=path) def normalize_typed_row(row: dict[str, Any], *, path: str) -> dict[str, Any]: """Canonicalize UUID and timestamp columns without weakening text equality.""" return _normalize_typed_row(row, path=path) def _canonical_json(value: Any) -> str: return json.dumps(value, ensure_ascii=False, separators=(",", ":"), sort_keys=True) def _sha256_json(value: Any) -> str: return hashlib.sha256(_canonical_json(value).encode("utf-8")).hexdigest() def sha256_text(value: str) -> str: return hashlib.sha256(value.encode("utf-8")).hexdigest() def _sql_literal(value: Any) -> str: if value is None: return "null" escaped = str(value).replace("\\", "\\\\").replace("'", "''") return "E'" + escaped + "'" def _jsonb(value: Any) -> str: return _sql_literal(_canonical_json(value)) + "::jsonb" def _require_applied_strict_proposal(proposal: dict[str, Any]) -> dict[str, Any]: if proposal.get("status") != "applied": raise ValueError("replay receipt requires proposal status='applied'") if not proposal.get("applied_at"): raise ValueError("replay receipt requires a non-null applied_at") if not proposal.get("applied_by_handle"): raise ValueError("replay receipt requires applied_by_handle") payload = proposal.get("payload") apply_payload = payload.get("apply_payload") if isinstance(payload, dict) else None if not isinstance(apply_payload, dict): raise ValueError("replay receipt requires a strict payload.apply_payload object") raw_version = apply_payload.get("contract_version") if proposal.get("proposal_type") == "approve_claim": if type(raw_version) is not int or raw_version not in {2, 3}: raise ValueError("approve_claim replay receipt requires integer contract_version 2 or 3") elif "contract_version" in apply_payload: raise ValueError("legacy replay receipt proposal types must omit contract_version") return apply_payload def _coalesced_json_agg(table: str, alias: str, where: str, order_by: str) -> str: return ( "coalesce((select jsonb_agg(to_jsonb(" + alias + ") order by " + order_by + ") " "from " + table + " " + alias + " where " + where + "), '[]'::jsonb)" ) def _id_filter(alias: str, values: list[Any]) -> str: if not values: return "false" rendered = ", ".join(f"{_sql_literal(value)}::uuid" for value in values) return f"{alias}.id in ({rendered})" def _or_filter(clauses: list[str]) -> str: if not clauses: return "false" return "(" + ") or (".join(clauses) + ")" def _build_add_edge_postflight_sql(apply_payload: dict[str, Any]) -> str: where = ( f"e.from_claim = {_sql_literal(apply_payload.get('from_claim'))}::uuid " f"and e.to_claim = {_sql_literal(apply_payload.get('to_claim'))}::uuid " f"and e.edge_type = {_sql_literal(apply_payload.get('edge_type'))}::edge_type" ) rows = _coalesced_json_agg("public.claim_edges", "e", where, "e.id::text") return f"select jsonb_build_object('claim_edges', {rows})::text;" def _build_attach_evidence_postflight_sql(apply_payload: dict[str, Any]) -> str: clauses = [] for row in apply_payload.get("evidence") or []: role = row.get("role") or "grounds" clauses.append( f"ce.claim_id = {_sql_literal(row.get('claim_id'))}::uuid " f"and ce.source_id = {_sql_literal(row.get('source_id'))}::uuid " f"and ce.role = {_sql_literal(role)}::evidence_role" ) rows = _coalesced_json_agg( "public.claim_evidence", "ce", _or_filter(clauses), "ce.claim_id::text, ce.source_id::text, ce.role::text", ) return f"select jsonb_build_object('claim_evidence', {rows})::text;" def _build_approve_claim_postflight_sql(apply_payload: dict[str, Any]) -> str: if apply_payload.get("contract_version") == 3: return _build_approve_claim_v3_postflight_sql(apply_payload) claims = apply_payload.get("claims") or [] sources = apply_payload.get("sources") or [] evidence = apply_payload.get("evidence") or [] edges = apply_payload.get("edges") or [] tools = apply_payload.get("reasoning_tools") or [] evidence_clauses = [] for row in evidence: role = row.get("role") or "grounds" evidence_clauses.append( f"ce.claim_id = {_sql_literal(row.get('claim_id'))}::uuid " f"and ce.source_id = {_sql_literal(row.get('source_id'))}::uuid " f"and ce.role = {_sql_literal(role)}::evidence_role" ) edge_clauses = [ f"e.from_claim = {_sql_literal(row.get('from_claim'))}::uuid " f"and e.to_claim = {_sql_literal(row.get('to_claim'))}::uuid " f"and e.edge_type = {_sql_literal(row.get('edge_type'))}::edge_type" for row in edges ] fields = { "claims": _coalesced_json_agg( "public.claims", "c", _id_filter("c", [row.get("id") for row in claims]), "c.id::text" ), "sources": _coalesced_json_agg( "public.sources", "s", _id_filter("s", [row.get("id") for row in sources]), "s.id::text" ), "claim_evidence": _coalesced_json_agg( "public.claim_evidence", "ce", _or_filter(evidence_clauses), "ce.claim_id::text, ce.source_id::text, ce.role::text", ), "claim_edges": _coalesced_json_agg("public.claim_edges", "e", _or_filter(edge_clauses), "e.id::text"), "reasoning_tools": _coalesced_json_agg( "public.reasoning_tools", "rt", _id_filter("rt", [row.get("id") for row in tools]), "rt.id::text", ), } arguments = ", ".join(f"{_sql_literal(name)}, {expression}" for name, expression in fields.items()) return f"select jsonb_build_object({arguments})::text;" def _build_approve_claim_v3_postflight_sql(apply_payload: dict[str, Any]) -> str: fields = { "claims": _coalesced_json_agg( "public.claims", "c", _id_filter("c", [row.get("id") for row in apply_payload.get("claims") or []]), "c.id::text", ), "sources": _coalesced_json_agg( "public.sources", "s", _id_filter("s", [row.get("id") for row in apply_payload.get("sources") or []]), "s.id::text", ), "claim_evidence": _coalesced_json_agg( "public.claim_evidence", "ce", _id_filter("ce", [row.get("id") for row in apply_payload.get("evidence") or []]), "ce.id::text", ), "claim_edges": _coalesced_json_agg( "public.claim_edges", "e", _id_filter("e", [row.get("id") for row in apply_payload.get("edges") or []]), "e.id::text", ), "claim_evidence_assessments": _coalesced_json_agg( "public.claim_evidence_assessments", "a", _id_filter("a", [row.get("id") for row in apply_payload.get("assessments") or []]), "a.id::text", ), "reasoning_tools": "'[]'::jsonb", } arguments = ", ".join(f"{_sql_literal(name)}, {expression}" for name, expression in fields.items()) return f"select jsonb_build_object({arguments})::text;" def _build_revise_strategy_postflight_sql(proposal: dict[str, Any], apply_payload: dict[str, Any]) -> str: strategy = apply_payload.get("strategy") or {} agent_id = apply_payload.get("agent_id") node_clauses = [] for row in apply_payload.get("strategy_nodes") or []: node_clauses.append( f"n.node_type = {_sql_literal(row.get('node_type'))} " f"and n.title = {_sql_literal(row.get('title'))} " f"and n.body = {_sql_literal(row.get('body'))} " f"and n.rank = {int(row.get('rank', 1))}" ) node_filter = _or_filter(node_clauses) return f"""with matched_strategy as ( select s.* from public.strategies s where s.agent_id = {_sql_literal(agent_id)}::uuid and s.diagnosis = {_sql_literal(strategy.get("diagnosis"))} and s.guiding_policy = {_sql_literal(strategy.get("guiding_policy"))} and s.proximate_objectives = {_jsonb(strategy.get("proximate_objectives"))} and s.created_at <= {_sql_literal(proposal.get("applied_at"))}::timestamptz order by s.version desc, s.id::text desc limit 1 ), matched_nodes as ( select n.* from public.strategy_nodes n join matched_strategy s on n.agent_id = s.agent_id and n.created_at = s.created_at where {node_filter} ) select jsonb_build_object( 'strategies', coalesce((select jsonb_agg(to_jsonb(s) order by s.id::text) from matched_strategy s), '[]'::jsonb), 'strategy_nodes', coalesce((select jsonb_agg(to_jsonb(n) order by n.rank, n.id::text) from matched_nodes n), '[]'::jsonb) )::text;""" def build_postflight_sql(proposal: dict[str, Any]) -> str: apply_payload = _require_applied_strict_proposal(proposal) proposal_type = proposal.get("proposal_type") if proposal_type == "add_edge": query = _build_add_edge_postflight_sql(apply_payload) elif proposal_type == "attach_evidence": query = _build_attach_evidence_postflight_sql(apply_payload) elif proposal_type == "approve_claim": query = _build_approve_claim_postflight_sql(apply_payload) elif proposal_type == "revise_strategy": query = _build_revise_strategy_postflight_sql(proposal, apply_payload) else: raise ValueError(f"replay receipt does not support proposal_type {proposal_type!r}") return UTC_SESSION_SQL + "\n" + query def expected_row_counts(proposal: dict[str, Any]) -> dict[str, int]: apply_payload = _require_applied_strict_proposal(proposal) proposal_type = proposal.get("proposal_type") if proposal_type == "add_edge": return {"claim_edges": 1} if proposal_type == "attach_evidence": return {"claim_evidence": len(apply_payload.get("evidence") or [])} if proposal_type == "approve_claim": if apply_payload.get("contract_version") == 3: return { "claims": len(apply_payload.get("claims") or []), "sources": len(apply_payload.get("sources") or []), "claim_evidence": len(apply_payload.get("evidence") or []), "claim_edges": len(apply_payload.get("edges") or []), "claim_evidence_assessments": len(apply_payload.get("assessments") or []), "reasoning_tools": 0, } return { "claims": len(apply_payload.get("claims") or []), "sources": len(apply_payload.get("sources") or []), "claim_evidence": len(apply_payload.get("evidence") or []), "claim_edges": len(apply_payload.get("edges") or []), "reasoning_tools": len(apply_payload.get("reasoning_tools") or []), } if proposal_type == "revise_strategy": return { "strategies": 1, "strategy_nodes": len(apply_payload.get("strategy_nodes") or []), } raise ValueError(f"replay receipt does not support proposal_type {proposal_type!r}") def _normalize_rows(canonical_rows: dict[str, Any], expected_counts: dict[str, int]) -> dict[str, list[dict[str, Any]]]: normalized: dict[str, list[dict[str, Any]]] = {} for table in expected_counts: rows = canonical_rows.get(table) if not isinstance(rows, list) or any(not isinstance(row, dict) for row in rows): raise ValueError(f"postflight {table} must be a list of row objects") typed_rows = [_normalize_typed_row(row, path=f"postflight.{table}") for row in rows] normalized[table] = sorted(typed_rows, key=_canonical_json) return normalized def _semantic_projection(row: dict[str, Any], fields: tuple[str, ...]) -> dict[str, Any]: return {field: _normalize_typed_value(field, row.get(field), path=f"semantic.{field}") for field in fields} def _expected_semantic_rows(proposal: dict[str, Any]) -> dict[str, list[dict[str, Any]]]: apply_payload = _require_applied_strict_proposal(proposal) proposal_type = proposal.get("proposal_type") if proposal_type == "add_edge": return { "claim_edges": [ { "from_claim": apply_payload.get("from_claim"), "to_claim": apply_payload.get("to_claim"), "edge_type": apply_payload.get("edge_type"), "weight": apply_payload.get("weight"), "created_by": None, } ] } if proposal_type == "attach_evidence": return { "claim_evidence": [ { "claim_id": row.get("claim_id"), "source_id": row.get("source_id"), "role": row.get("role") or "grounds", "weight": row.get("weight"), "created_by": None, } for row in apply_payload.get("evidence") or [] ] } if proposal_type == "approve_claim": if apply_payload.get("contract_version") == 3: return _expected_v3_semantic_rows(proposal, apply_payload) agent_id = apply_payload.get("agent_id") return { "claims": [ { "id": row.get("id"), "type": row.get("type"), "text": row.get("text"), "status": row.get("status", "open"), "confidence": row.get("confidence"), "tags": row.get("tags") or [], "created_by": row.get("created_by", agent_id), "superseded_by": row.get("superseded_by"), } for row in apply_payload.get("claims") or [] ], "sources": [ { "id": row.get("id"), "source_type": row.get("source_type"), "url": row.get("url"), "storage_path": row.get("storage_path"), "excerpt": row.get("excerpt"), "hash": row.get("hash"), "created_by": row.get("created_by", agent_id), } for row in apply_payload.get("sources") or [] ], "claim_evidence": [ { "claim_id": row.get("claim_id"), "source_id": row.get("source_id"), "role": row.get("role") or "grounds", "weight": row.get("weight"), "created_by": row.get("created_by", agent_id), } for row in apply_payload.get("evidence") or [] ], "claim_edges": [ { "from_claim": row.get("from_claim"), "to_claim": row.get("to_claim"), "edge_type": row.get("edge_type"), "weight": row.get("weight"), "created_by": row.get("created_by", agent_id), } for row in apply_payload.get("edges") or [] ], "reasoning_tools": [ { "id": row.get("id"), "agent_id": row.get("agent_id", agent_id), "name": row.get("name"), "description": row.get("description"), "category": row.get("category"), } for row in apply_payload.get("reasoning_tools") or [] ], } if proposal_type == "revise_strategy": strategy = apply_payload.get("strategy") or {} agent_id = apply_payload.get("agent_id") return { "strategies": [ { "agent_id": agent_id, "diagnosis": strategy.get("diagnosis"), "guiding_policy": strategy.get("guiding_policy"), "proximate_objectives": strategy.get("proximate_objectives"), "active": True, } ], "strategy_nodes": [ { "agent_id": agent_id, "node_type": row.get("node_type"), "title": row.get("title"), "body": row.get("body"), "rank": row.get("rank", 1), "status": "active", "horizon": None, "measure": None, "source_ref": None, "metadata": {}, } for row in apply_payload.get("strategy_nodes") or [] ], } raise ValueError(f"replay receipt does not support proposal_type {proposal_type!r}") def _expected_v3_semantic_rows( proposal: dict[str, Any], apply_payload: dict[str, Any] ) -> dict[str, list[dict[str, Any]]]: proposal_id = _canonical_uuid(proposal.get("id"), path="proposal.id") agent_id = apply_payload.get("agent_id") polarity_to_role = {"supports": "grounds", "challenges": "contradicts", "illustrates": "illustrates"} return { "claims": [ { "id": row.get("id"), "owner_agent_id": row.get("owner_agent_id"), "type": row.get("type"), "text": row.get("proposition"), "proposition": row.get("proposition"), "body_markdown": row.get("body_markdown"), "scope": row.get("scope"), "access_scope": row.get("access_scope"), "status": row.get("status", "active"), "admission_state": "admitted", "revision_criteria": row.get("revision_criteria"), "revision_kind": "original", "supersedes_id": None, "confidence": None, "tags": row.get("tags") or [], "created_by": row.get("created_by", agent_id), "superseded_by": None, "accepted_by_proposal_id": proposal_id, } for row in apply_payload.get("claims") or [] ], "sources": [ { "id": row.get("id"), "source_type": row.get("source_type"), "url": row.get("canonical_url"), "storage_path": row.get("storage_uri"), "excerpt": row.get("excerpt"), "hash": row.get("content_hash"), "created_by": row.get("created_by", agent_id), "captured_at": row.get("captured_at"), "canonical_url": row.get("canonical_url"), "storage_uri": row.get("storage_uri"), "content_hash": row.get("content_hash"), "access_scope": row.get("access_scope"), "ingestion_origin": row.get("ingestion_origin"), "provenance_status": row.get("provenance_status"), "source_class": row.get("source_class"), "auto_promotion_policy": row.get("auto_promotion_policy"), "accepted_by_proposal_id": proposal_id, } for row in apply_payload.get("sources") or [] ], "claim_evidence": [ { "id": row.get("id"), "claim_id": row.get("claim_id"), "source_id": row.get("source_id"), "role": polarity_to_role.get(row.get("polarity")), "weight": None, "created_by": row.get("created_by", agent_id), "excerpt": row.get("excerpt"), "locator_json": row.get("locator_json"), "source_content_hash": row.get("source_content_hash"), "rationale": row.get("rationale"), "polarity": row.get("polarity"), "accepted_from_proposal_id": proposal_id, } for row in apply_payload.get("evidence") or [] ], "claim_edges": [ { "id": row.get("id"), "from_claim": row.get("from_claim"), "to_claim": row.get("to_claim"), "edge_type": "requires" if row.get("relation_type") == "depends_on" else row.get("relation_type"), "weight": None, "created_by": row.get("created_by", agent_id), "relation_type": row.get("relation_type"), "rationale": row.get("rationale"), "scope_or_conditions": row.get("scope_or_conditions"), "accepted_by_proposal_id": proposal_id, } for row in apply_payload.get("edges") or [] ], "claim_evidence_assessments": [ { "id": row.get("id"), "claim_id": row.get("claim_id"), "support_tier": row.get("support_tier"), "challenge_tier": row.get("challenge_tier"), "overall_state": row.get("overall_state"), "rationale": row.get("rationale"), "evidence_set_hash": row.get("evidence_set_hash"), "accepted_by_proposal_id": proposal_id, "supersedes_assessment_id": row.get("supersedes_assessment_id"), } for row in apply_payload.get("assessments") or [] ], "reasoning_tools": [], } def _assert_semantic_rows_match(proposal: dict[str, Any], rows: dict[str, list[dict[str, Any]]]) -> None: expected = _expected_semantic_rows(proposal) for table, expected_rows in expected.items(): fields = tuple(expected_rows[0]) if expected_rows else () expected_projected = [_semantic_projection(row, fields) for row in expected_rows] actual_projected = [_semantic_projection(row, fields) for row in rows.get(table, [])] if sorted(expected_projected, key=_canonical_json) != sorted(actual_projected, key=_canonical_json): raise ValueError( f"row-level postflight semantic mismatch for {table}; " "canonical values do not match the immutable strict payload" ) def build_replay_receipt( proposal: dict[str, Any], canonical_rows: dict[str, Any], *, apply_sql_sha256: str, apply_sql_source: str, exported_at_utc: str | None = None, ) -> dict[str, Any]: if len(apply_sql_sha256) != 64 or any(character not in "0123456789abcdef" for character in apply_sql_sha256): raise ValueError("apply_sql_sha256 must be a lowercase SHA-256 hex digest") if apply_sql_source not in {"exact_executed_sql", "reconstructed_current_engine"}: raise ValueError("invalid apply_sql_source") apply_payload = _require_applied_strict_proposal(proposal) expected = expected_row_counts(proposal) rows = _normalize_rows(canonical_rows, expected) actual = {table: len(table_rows) for table, table_rows in rows.items()} mismatches = { table: {"expected": expected[table], "actual": actual.get(table, 0)} for table in expected if actual.get(table, 0) != expected[table] } if mismatches: raise ValueError(f"row-level postflight count mismatch: {mismatches}") _assert_semantic_rows_match(proposal, rows) proposal_envelope = { "id": _canonical_uuid(proposal.get("id"), path="proposal.id"), "proposal_type": proposal.get("proposal_type"), "status": proposal.get("status"), "payload": proposal.get("payload"), "reviewed_by_handle": proposal.get("reviewed_by_handle"), "reviewed_by_agent_id": _normalize_typed_value( "reviewed_by_agent_id", proposal.get("reviewed_by_agent_id"), path="proposal.reviewed_by_agent_id" ), "reviewed_at": _normalize_typed_value("reviewed_at", proposal.get("reviewed_at"), path="proposal.reviewed_at"), "review_note": proposal.get("review_note"), "applied_by_handle": proposal.get("applied_by_handle"), "applied_by_agent_id": _normalize_typed_value( "applied_by_agent_id", proposal.get("applied_by_agent_id"), path="proposal.applied_by_agent_id" ), "applied_at": _normalize_typed_value("applied_at", proposal.get("applied_at"), path="proposal.applied_at"), } row_hashes = {table: [_sha256_json(row) for row in table_rows] for table, table_rows in rows.items()} table_hashes = {table: _sha256_json(table_rows) for table, table_rows in rows.items()} replay_material = { "receipt_contract_version": RECEIPT_CONTRACT_VERSION, "apply_engine": { "apply_sql_sha256": apply_sql_sha256, "source": apply_sql_source, }, "proposal": proposal_envelope, "canonical_rows": rows, } return { **replay_material, "artifact": "kb_apply_replay_receipt", "exported_at_utc": canonical_utc_timestamp( exported_at_utc or datetime.now(timezone.utc).isoformat(), path="exported_at_utc" ), "expected_row_counts": expected, "actual_row_counts": actual, "checks": { "proposal_applied": True, "strict_apply_payload_present": True, "applied_at_present": True, "row_level_postflight_exact": True, "semantic_rows_match_strict_payload": True, }, "hashes": { "apply_payload_sha256": _sha256_json(apply_payload), "proposal_payload_sha256": _sha256_json(proposal.get("payload")), "canonical_rows_sha256": _sha256_json(rows), "row_sha256": row_hashes, "table_sha256": table_hashes, "replay_material_sha256": _sha256_json(replay_material), }, "replay_ready": True, "privacy": "private receipt; may contain claim bodies and source excerpts; do not commit", } def validate_replay_receipt( receipt: dict[str, Any], *, expected_proposal_id: str | None = None, ) -> dict[str, Any]: """Rebuild and require the exact private replay-receipt contract. Canonical JSON comparison is deliberate: Python equality treats booleans and integers as interchangeable, which is unsafe for authorization and receipt fields. """ if not isinstance(receipt, dict): raise ValueError("replay receipt must be an object") proposal = receipt.get("proposal") rows = receipt.get("canonical_rows") apply_engine = receipt.get("apply_engine") if not isinstance(proposal, dict) or not isinstance(rows, dict) or not isinstance(apply_engine, dict): raise ValueError("replay receipt is missing proposal, canonical rows, or apply-engine metadata") if expected_proposal_id is not None and proposal.get("id") != _canonical_uuid( expected_proposal_id, path="expected_proposal_id" ): raise ValueError("replay receipt proposal id does not match") try: rebuilt = build_replay_receipt( proposal, rows, apply_sql_sha256=apply_engine.get("apply_sql_sha256"), apply_sql_source=apply_engine.get("source"), exported_at_utc=receipt.get("exported_at_utc"), ) except (KeyError, TypeError, ValueError) as exc: raise ValueError("replay receipt failed full contract validation") from exc if _canonical_json(receipt) != _canonical_json(rebuilt): raise ValueError("replay receipt hashes, counts, rows, or contract fields are internally inconsistent") return rebuilt def resolve_receipt_path( proposal_id: str, *, receipt_out: str | None = None, receipt_dir: str | None = None, ) -> Path: if receipt_out: return Path(receipt_out) root = Path(receipt_dir or os.environ.get("KB_APPLY_RECEIPT_DIR") or DEFAULT_RECEIPT_DIR) return root / f"{proposal_id}.json" def write_private_receipt(path: Path, receipt: dict[str, Any]) -> None: path.parent.mkdir(parents=True, exist_ok=True, mode=0o700) payload = json.dumps(receipt, ensure_ascii=False, indent=2, sort_keys=True) + "\n" fd, temporary_name = tempfile.mkstemp(prefix=f".{path.name}.", dir=str(path.parent)) try: os.fchmod(fd, 0o600) with os.fdopen(fd, "w", encoding="utf-8") as handle: handle.write(payload) handle.flush() os.fsync(handle.fileno()) os.replace(temporary_name, path) os.chmod(path, 0o600) except Exception: try: os.close(fd) except OSError: pass try: os.unlink(temporary_name) except FileNotFoundError: pass raise