teleo-infrastructure/scripts/run_leo_local_ingestion_proposal_canary.py

1535 lines
70 KiB
Python

#!/usr/bin/env python3
"""Ingest source-only fixtures into review staging in disposable Postgres.
The canary parses a raw document or repo-native Telegram JSONL transcript,
replays a versioned deterministic extraction sidecar, persists exact source
locations, normalizes the candidates, and stages one ``pending_review``
proposal. Representative canonical ``public.*`` rows are fingerprinted before
and after. No review, apply, network access, production target, or durable
Docker volume is used.
"""
from __future__ import annotations
import argparse
import hashlib
import json
import re
import shutil
import subprocess
import sys
import time
import uuid
from pathlib import Path
from typing import Any
HERE = Path(__file__).resolve().parent
REPO_ROOT = HERE.parent
sys.path.insert(0, str(HERE))
import apply_proposal as ap # noqa: E402
import stage_normalized_proposal as normalized_stage # noqa: E402
SCHEMA = "livingip.workingLeoLocalIngestionProposalCanary.v2"
SUITE_SCHEMA = "livingip.workingLeoLocalIngestionProposalSuite.v2"
FIXTURE_SCHEMA = "livingip.workingLeoSourceIngestionScenario.v2"
DEFAULT_DOCUMENT_FIXTURE = REPO_ROOT / "fixtures" / "working-leo" / "document-ingestion-v2.scenario.json"
DEFAULT_TELEGRAM_FIXTURE = REPO_ROOT / "fixtures" / "working-leo" / "telegram-transcript-ingestion-v1.scenario.json"
DEFAULT_FIXTURE = DEFAULT_DOCUMENT_FIXTURE
DEFAULT_FIXTURES = (DEFAULT_DOCUMENT_FIXTURE, DEFAULT_TELEGRAM_FIXTURE)
CONTAINER_LABEL = "livingip.canary=working-leo-local-ingestion"
CANONICAL_TABLES = ("claims", "sources", "claim_evidence", "claim_edges")
SEED_CLAIM_A = "00000000-0000-4000-8000-000000000101"
SEED_CLAIM_B = "00000000-0000-4000-8000-000000000102"
SEED_SOURCE = "00000000-0000-4000-8000-000000000201"
class CanaryError(RuntimeError):
"""Raised when a fixture or disposable runtime fails closed."""
def sha256_bytes(value: bytes) -> str:
return hashlib.sha256(value).hexdigest()
def canonical_json_bytes(value: Any) -> bytes:
return json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=True).encode()
def canonical_sha256(value: Any) -> str:
return sha256_bytes(canonical_json_bytes(value))
def normalized_segment_manifest(segments: list[dict[str, Any]]) -> list[dict[str, Any]]:
"""Return the complete normalized provenance identity for replay hashing."""
return [
{
"id": segment["id"],
"locator": segment["locator"],
"json_pointer": segment["json_pointer"],
"content_sha256": segment["content_sha256"],
"text_sha256": segment["text_sha256"],
}
for segment in segments
]
def replay_identity_payload(
*,
artifact_sha256: str,
artifact_format: str,
source_identity: str,
source_locator: str,
normalized_segments_sha256: str,
extractor: dict[str, str],
extraction_spec_sha256: str,
) -> dict[str, Any]:
"""Build the explicit source-to-extraction identity used by every row ID."""
return {
"artifact_sha256": artifact_sha256,
"artifact_format": artifact_format,
"source_identity": source_identity,
"source_locator": source_locator,
"normalized_segments_sha256": normalized_segments_sha256,
"extractor": extractor,
"extraction_spec_sha256": extraction_spec_sha256,
}
def canonical_snapshot_complete(snapshot: dict[str, Any]) -> bool:
return set(snapshot) == set(CANONICAL_TABLES) and all(
isinstance(snapshot.get(table), list) and bool(snapshot[table]) for table in CANONICAL_TABLES
)
def stable_uuid(seed: str, label: str) -> str:
return str(uuid.uuid5(uuid.NAMESPACE_URL, f"livingip:working-leo-ingestion:{seed}:{label}"))
def _require_object(value: Any, label: str) -> dict[str, Any]:
if not isinstance(value, dict):
raise CanaryError(f"{label} must be an object")
return value
def _require_list(value: Any, label: str) -> list[Any]:
if not isinstance(value, list):
raise CanaryError(f"{label} must be a list")
return value
def _require_text(value: Any, label: str) -> str:
if not isinstance(value, str) or not value.strip():
raise CanaryError(f"{label} must be a non-empty string")
return value.strip()
def _safe_source_key(value: str) -> str:
normalized = re.sub(r"[^a-z0-9._:-]+", "_", value.lower()).strip("_")
if not normalized:
raise CanaryError(f"could not derive a stable source key from {value!r}")
return normalized[:128]
def _load_plain_text_segments(raw: bytes, source: dict[str, Any]) -> list[dict[str, Any]]:
try:
text = raw.decode("utf-8", errors="strict")
except UnicodeDecodeError as exc:
raise CanaryError(f"plain_text artifact must be strict UTF-8: {exc}") from exc
locator = _require_text(source.get("locator"), "source.locator")
segments: list[dict[str, Any]] = []
cursor = 0
for part in re.split(r"\n[ \t]*\n", text):
part_start = text.find(part, cursor)
cursor = part_start + len(part)
body = part.strip()
if not body:
continue
start = part_start + part.find(body)
index = len(segments) + 1
canonical_record = {"paragraph": index, "text": body}
segments.append(
{
"id": f"paragraph-{index}",
"body": body,
"locator": f"{locator}#paragraph-{index}",
"json_pointer": None,
"content_sha256": canonical_sha256(canonical_record),
"text_sha256": sha256_bytes(body.encode()),
"metadata": {"paragraph": index, "char_start": start, "char_end": start + len(body)},
}
)
if not segments:
raise CanaryError("plain_text artifact contains no non-empty paragraphs")
return segments
def _load_telegram_jsonl_segments(raw: bytes) -> list[dict[str, Any]]:
try:
text = raw.decode("utf-8", errors="strict")
except UnicodeDecodeError as exc:
raise CanaryError(f"telegram_jsonl artifact must be strict UTF-8: {exc}") from exc
segments: list[dict[str, Any]] = []
seen: set[tuple[int, int]] = set()
for line_number, line in enumerate(text.splitlines(), start=1):
if not line.strip():
continue
try:
record = json.loads(line)
except json.JSONDecodeError as exc:
raise CanaryError(f"telegram JSONL line {line_number} is invalid JSON: {exc}") from exc
record = _require_object(record, f"telegram JSONL line {line_number}")
chat_id = record.get("chat_id")
message_id = record.get("message_id")
message = record.get("message")
if isinstance(chat_id, bool) or not isinstance(chat_id, int):
raise CanaryError(f"telegram JSONL line {line_number}.chat_id must be an integer")
if isinstance(message_id, bool) or not isinstance(message_id, int):
raise CanaryError(f"telegram JSONL line {line_number}.message_id must be an integer")
if not isinstance(message, str) or not message.strip():
raise CanaryError(f"telegram JSONL line {line_number}.message must be non-empty")
key = (chat_id, message_id)
if key in seen:
raise CanaryError(f"telegram JSONL repeats chat/message identity {key}")
seen.add(key)
body = message.strip()
segments.append(
{
"id": f"message-{chat_id}-{message_id}",
"body": body,
"locator": f"telegram://chat/{chat_id}/message/{message_id}",
"json_pointer": f"jsonl://line/{line_number}/message",
"content_sha256": canonical_sha256(record),
"text_sha256": sha256_bytes(body.encode()),
"metadata": {
"line_number": line_number,
"ts": record.get("ts"),
"chat_id": chat_id,
"chat_title": record.get("chat_title"),
"message_id": message_id,
"type": record.get("type"),
"username": record.get("username"),
"display_name": record.get("display_name"),
"user_id": record.get("user_id"),
"reply_to": record.get("reply_to"),
"synthetic": record.get("synthetic") is True,
},
}
)
if not segments:
raise CanaryError("telegram_jsonl artifact contains no messages")
return segments
def _load_segments(raw: bytes, artifact_format: str, source: dict[str, Any]) -> list[dict[str, Any]]:
if artifact_format == "plain_text":
return _load_plain_text_segments(raw, source)
if artifact_format == "telegram_jsonl":
return _load_telegram_jsonl_segments(raw)
raise CanaryError("artifact.format must be plain_text or telegram_jsonl")
def load_fixture(path: Path) -> tuple[dict[str, Any], dict[str, Any]]:
scenario_path = path.resolve()
try:
scenario_raw = scenario_path.read_bytes()
scenario = json.loads(scenario_raw)
except (OSError, json.JSONDecodeError) as exc:
raise CanaryError(f"scenario is not readable JSON: {exc}") from exc
if not isinstance(scenario, dict) or scenario.get("schema") != FIXTURE_SCHEMA:
raise CanaryError(f"scenario schema must be {FIXTURE_SCHEMA}")
artifact = _require_object(scenario.get("artifact"), "artifact")
source = _require_object(scenario.get("source"), "source")
extractor = _require_object(scenario.get("extractor"), "extractor")
extraction = _require_object(scenario.get("extraction"), "extraction")
artifact_rel = Path(_require_text(artifact.get("path"), "artifact.path"))
if artifact_rel.is_absolute():
raise CanaryError("artifact.path must be relative to the scenario")
artifact_path = (scenario_path.parent / artifact_rel).resolve()
try:
artifact_path.relative_to(scenario_path.parent.resolve())
except ValueError as exc:
raise CanaryError("artifact.path must remain inside the scenario directory") from exc
try:
raw = artifact_path.read_bytes()
except OSError as exc:
raise CanaryError(f"source artifact is unreadable: {exc}") from exc
if not raw:
raise CanaryError("source artifact must not be empty")
artifact_format = _require_text(artifact.get("format"), "artifact.format")
extractor_name = _require_text(extractor.get("name"), "extractor.name")
extractor_version = _require_text(extractor.get("version"), "extractor.version")
required_source = ("identity", "source_key", "source_type", "title", "locator", "metadata")
missing_source = [key for key in required_source if source.get(key) in (None, "")]
if missing_source:
raise CanaryError(f"source is missing: {', '.join(missing_source)}")
if source["source_type"] not in ap.SOURCE_TYPES:
raise CanaryError(f"source.source_type must be one of {sorted(ap.SOURCE_TYPES)}")
if not isinstance(source.get("metadata"), dict):
raise CanaryError("source.metadata must be an object")
source_identity = _require_text(source.get("identity"), "source.identity")
source_locator = _require_text(source.get("locator"), "source.locator")
source = {**source, "identity": source_identity, "locator": source_locator}
segments = _load_segments(raw, artifact_format, source)
segment_by_id = {segment["id"]: segment for segment in segments}
claims = _require_list(extraction.get("claims"), "extraction.claims")
duplicates = _require_list(extraction.get("duplicates"), "extraction.duplicates")
conflicts = _require_list(extraction.get("conflicts"), "extraction.conflicts")
if not claims:
raise CanaryError("extraction.claims must contain at least one review candidate")
claim_keys: set[str] = set()
normalized_claims: list[dict[str, Any]] = []
evidence_count = 0
for claim_index, raw_claim in enumerate(claims):
claim = _require_object(raw_claim, f"extraction.claims[{claim_index}]")
claim_key = _require_text(claim.get("claim_key"), f"extraction.claims[{claim_index}].claim_key")
if claim_key in claim_keys:
raise CanaryError(f"duplicate claim_key {claim_key}")
claim_keys.add(claim_key)
claim_type = _require_text(claim.get("type"), f"extraction.claims[{claim_index}].type")
if claim_type not in ap.CLAIM_TYPES:
raise CanaryError(f"claim {claim_key} has unsupported type {claim_type}")
confidence = claim.get("confidence")
if isinstance(confidence, bool) or not isinstance(confidence, (int, float)) or not 0 <= confidence <= 1:
raise CanaryError(f"claim {claim_key} confidence must be between 0 and 1")
evidence_rows = _require_list(claim.get("evidence"), f"claim {claim_key}.evidence")
if not evidence_rows:
raise CanaryError(f"claim {claim_key} requires evidence")
normalized_evidence: list[dict[str, Any]] = []
for evidence_index, raw_evidence in enumerate(evidence_rows):
evidence = _require_object(raw_evidence, f"claim {claim_key}.evidence[{evidence_index}]")
segment_id = _require_text(evidence.get("segment_id"), f"claim {claim_key} evidence segment_id")
segment = segment_by_id.get(segment_id)
if segment is None:
raise CanaryError(f"claim {claim_key} evidence references unknown segment {segment_id}")
excerpt = _require_text(evidence.get("excerpt"), f"claim {claim_key} evidence excerpt")
if excerpt not in segment["body"]:
raise CanaryError(f"claim {claim_key} evidence excerpt is not an exact segment substring")
role = _require_text(evidence.get("role"), f"claim {claim_key} evidence role")
if role not in ap.EVIDENCE_ROLES:
raise CanaryError(f"claim {claim_key} evidence has unsupported role {role}")
normalized_evidence.append(
{
**evidence,
"segment_id": segment_id,
"excerpt": excerpt,
"role": role,
"source_locator": segment["locator"],
"source_json_pointer": segment["json_pointer"],
"source_content_sha256": segment["content_sha256"],
"source_text_sha256": segment["text_sha256"],
}
)
evidence_count += 1
body = _require_text(claim.get("body"), f"claim {claim_key}.body")
if not any(body in segment_by_id[row["segment_id"]]["body"] for row in normalized_evidence):
raise CanaryError(f"claim {claim_key} body must be an exact substring of its evidence segments")
edges = _require_list(claim.get("edges", []), f"claim {claim_key}.edges")
normalized_claims.append(
{
**claim,
"claim_key": claim_key,
"type": claim_type,
"confidence": confidence,
"text": _require_text(claim.get("text"), f"claim {claim_key}.text"),
"body": body,
"metadata": _require_object(claim.get("metadata", {}), f"claim {claim_key}.metadata"),
"evidence": normalized_evidence,
"edges": edges,
}
)
normalized_duplicates: list[dict[str, Any]] = []
for duplicate_index, raw_duplicate in enumerate(duplicates):
duplicate = _require_object(raw_duplicate, f"extraction.duplicates[{duplicate_index}]")
segment_id = _require_text(duplicate.get("segment_id"), f"duplicate {duplicate_index}.segment_id")
target = _require_text(
duplicate.get("duplicate_of_claim_key"), f"duplicate {duplicate_index}.duplicate_of_claim_key"
)
if target not in claim_keys:
raise CanaryError(f"duplicate {duplicate_index} references unknown claim {target}")
segment = segment_by_id.get(segment_id)
if segment is None:
raise CanaryError(f"duplicate {duplicate_index} references unknown segment {segment_id}")
excerpt = _require_text(duplicate.get("excerpt"), f"duplicate {duplicate_index}.excerpt")
if excerpt not in segment["body"]:
raise CanaryError(f"duplicate {duplicate_index} excerpt is not an exact segment substring")
normalized_duplicates.append(
{
**duplicate,
"segment_id": segment_id,
"duplicate_of_claim_key": target,
"excerpt": excerpt,
"source_locator": segment["locator"],
"source_json_pointer": segment["json_pointer"],
"source_content_sha256": segment["content_sha256"],
"source_text_sha256": segment["text_sha256"],
}
)
normalized_conflicts: list[dict[str, Any]] = []
for conflict_index, raw_conflict in enumerate(conflicts):
conflict = _require_object(raw_conflict, f"extraction.conflicts[{conflict_index}]")
from_key = _require_text(conflict.get("from_claim_key"), f"conflict {conflict_index}.from_claim_key")
to_key = _require_text(conflict.get("to_claim_key"), f"conflict {conflict_index}.to_claim_key")
relationship = _require_text(conflict.get("relationship"), f"conflict {conflict_index}.relationship")
if from_key not in claim_keys or to_key not in claim_keys:
raise CanaryError(f"conflict {conflict_index} must reference produced claim keys")
if relationship != "contradicts":
raise CanaryError("fixture conflicts must use relationship=contradicts")
matching_edge = any(
claim["claim_key"] == from_key
and any(edge.get("edge_type") == relationship and edge.get("target") == to_key for edge in claim["edges"])
for claim in normalized_claims
)
if not matching_edge:
raise CanaryError(f"conflict {from_key}->{to_key} has no matching candidate edge")
normalized_conflicts.append({**conflict, "from_claim_key": from_key, "to_claim_key": to_key})
artifact_sha256 = sha256_bytes(raw)
segment_manifest = normalized_segment_manifest(segments)
source_content_sha256 = canonical_sha256(segment_manifest)
extraction_spec_sha256 = canonical_sha256(extraction)
extractor_identity = {"name": extractor_name, "version": extractor_version}
replay_components = replay_identity_payload(
artifact_sha256=artifact_sha256,
artifact_format=artifact_format,
source_identity=source_identity,
source_locator=source_locator,
normalized_segments_sha256=source_content_sha256,
extractor=extractor_identity,
extraction_spec_sha256=extraction_spec_sha256,
)
replay_identity_sha256 = canonical_sha256(replay_components)
fixture = {
**scenario,
"artifact": {**artifact, "resolved_path": str(artifact_path)},
"source": source,
"extractor": extractor_identity,
"segments": segments,
"extraction": {
"claims": normalized_claims,
"duplicates": normalized_duplicates,
"conflicts": normalized_conflicts,
},
}
receipt = {
"scenario_path": str(scenario_path),
"scenario_sha256": sha256_bytes(scenario_raw),
"artifact_path": str(artifact_path),
"artifact_format": artifact_format,
"artifact_sha256": artifact_sha256,
"source_content_sha256": source_content_sha256,
"source_identity": source_identity,
"source_locator": source_locator,
"extractor": extractor_identity,
"extraction_spec_sha256": extraction_spec_sha256,
"replay_identity_components": replay_components,
"replay_identity_sha256": replay_identity_sha256,
"counts": {
"source_segments": len(segments),
"claim_candidates": len(normalized_claims),
"evidence_candidates": evidence_count,
"duplicate_judgments": len(normalized_duplicates),
"conflict_relationships": len(normalized_conflicts),
},
}
return fixture, receipt
def build_row_ids(input_receipt: dict[str, Any], fixture: dict[str, Any]) -> dict[str, Any]:
replay_seed = input_receipt["replay_identity_sha256"]
claim_ids = {
claim["claim_key"]: stable_uuid(replay_seed, f"claim-extraction:{claim['claim_key']}")
for claim in fixture["extraction"]["claims"]
}
evidence_ids: dict[str, str] = {}
for claim in fixture["extraction"]["claims"]:
for index, _evidence in enumerate(claim["evidence"]):
key = f"{claim['claim_key']}:{index}"
evidence_ids[key] = stable_uuid(replay_seed, f"evidence-extraction:{key}")
duplicate_ids = {
str(index): stable_uuid(replay_seed, f"duplicate-assessment:{index}")
for index, _duplicate in enumerate(fixture["extraction"]["duplicates"])
}
conflict_ids = {
str(index): stable_uuid(replay_seed, f"conflict-assessment:{index}")
for index, _conflict in enumerate(fixture["extraction"]["conflicts"])
}
return {
"source_capture_id": stable_uuid(replay_seed, "source-capture"),
"claim_extraction_ids": claim_ids,
"evidence_extraction_ids": evidence_ids,
"duplicate_assessment_ids": duplicate_ids,
"conflict_assessment_ids": conflict_ids,
"parent_proposal_id": stable_uuid(replay_seed, "rich-parent-proposal"),
}
def _segment_source_key(source_key: str, segment_id: str) -> str:
return _safe_source_key(f"{source_key}__{segment_id}")
def build_parent_packet(
fixture: dict[str, Any], input_receipt: dict[str, Any], row_ids: dict[str, Any]
) -> dict[str, Any]:
source = fixture["source"]
claims = fixture["extraction"]["claims"]
segment_by_id = {segment["id"]: segment for segment in fixture["segments"]}
referenced_segment_ids: list[str] = []
for claim in claims:
for evidence in claim["evidence"]:
if evidence["segment_id"] not in referenced_segment_ids:
referenced_segment_ids.append(evidence["segment_id"])
for duplicate in fixture["extraction"]["duplicates"]:
if duplicate["segment_id"] not in referenced_segment_ids:
referenced_segment_ids.append(duplicate["segment_id"])
source_candidates = []
for segment_id in referenced_segment_ids:
segment = segment_by_id[segment_id]
segment_source_key = _segment_source_key(source["source_key"], segment_id)
provenance = {
"artifact_sha256": input_receipt["artifact_sha256"],
"segment_id": segment_id,
"locator": segment["locator"],
"json_pointer": segment["json_pointer"],
"content_sha256": segment["content_sha256"],
"text_sha256": segment["text_sha256"],
}
source_candidates.append(
{
"source_key": segment_source_key,
"source_type": "dm" if input_receipt["artifact_format"] == "telegram_jsonl" else source["source_type"],
"title": f"{source['title']} - {segment_id}",
"storage_path": segment["locator"],
"url": None,
"source_quality": json.dumps(provenance, sort_keys=True, separators=(",", ":")),
"usage_limits": "Review-only exact excerpt; no canonical apply is authorized.",
"key_excerpt": segment["body"],
"content_sha256": segment["content_sha256"],
}
)
claim_candidates = []
for claim in claims:
claim_candidates.append(
{
"claim_key": claim["claim_key"],
"type": claim["type"],
"confidence": claim["confidence"],
"text": claim["text"],
"body": claim["body"],
"evidence_tier": "source_artifact_exact_location",
"needs_research": claim["metadata"].get("needs_research", False),
"evidence": [
{
"source_key": _segment_source_key(source["source_key"], evidence["segment_id"]),
"role": evidence["role"],
}
for evidence in claim["evidence"]
],
"edges": claim["edges"],
}
)
ingestion_manifest = {
"scenario_schema": fixture["schema"],
"scenario_sha256": input_receipt["scenario_sha256"],
"artifact_format": input_receipt["artifact_format"],
"artifact_sha256": input_receipt["artifact_sha256"],
"source_content_sha256": input_receipt["source_content_sha256"],
"source_identity": input_receipt["source_identity"],
"source_locator": input_receipt["source_locator"],
"extractor": input_receipt["extractor"],
"extraction_spec_sha256": input_receipt["extraction_spec_sha256"],
"replay_identity_components": input_receipt["replay_identity_components"],
"replay_identity_sha256": input_receipt["replay_identity_sha256"],
"segments": normalized_segment_manifest(fixture["segments"]),
"row_ids": row_ids,
"candidate_counts": input_receipt["counts"],
}
return {
"id": row_ids["parent_proposal_id"],
"proposal_type": "attach_evidence",
"status": "pending_review",
"proposed_by_handle": "leo",
"proposed_by_agent_id": None,
"channel": "local_ingestion_canary",
"source_ref": (
f"local-ingestion:{input_receipt['artifact_sha256']}:"
f"replay={input_receipt['replay_identity_sha256']}:capture={row_ids['source_capture_id']}"
),
"rationale": "Stage source-linked candidate claims for review without canonical apply.",
"payload": {
"ingestion_manifest": ingestion_manifest,
"claim_candidates": claim_candidates,
"source_candidates": source_candidates,
"dedupe_conflict_assessment": {
"database_search_query": " ".join(claim["claim_key"].replace("_", " ") for claim in claims),
"duplicates": fixture["extraction"]["duplicates"],
"conflicts": fixture["extraction"]["conflicts"],
"review_required": True,
},
},
}
def _independent_planned_uuid(parent_proposal_id: str, kind: str, key: str) -> str:
"""Reproduce the public deterministic-ID contract without calling the planner."""
return str(uuid.uuid5(uuid.NAMESPACE_URL, f"teleo:kb-rich-contract:{parent_proposal_id}:{kind}:{key}"))
def expected_planned_graph_identity(fixture: dict[str, Any], row_ids: dict[str, Any]) -> dict[str, Any]:
"""Derive planned row IDs and FK identities directly from normalized source candidates."""
parent_id = row_ids["parent_proposal_id"]
claims = fixture["extraction"]["claims"]
claim_ids = {
claim["claim_key"]: _independent_planned_uuid(parent_id, "claim", claim["claim_key"]) for claim in claims
}
referenced_segment_ids: list[str] = []
for claim in claims:
for evidence in claim["evidence"]:
if evidence["segment_id"] not in referenced_segment_ids:
referenced_segment_ids.append(evidence["segment_id"])
for duplicate in fixture["extraction"]["duplicates"]:
if duplicate["segment_id"] not in referenced_segment_ids:
referenced_segment_ids.append(duplicate["segment_id"])
segment_source_ids = {
segment_id: _independent_planned_uuid(
parent_id,
"source",
_segment_source_key(fixture["source"]["source_key"], segment_id),
)
for segment_id in referenced_segment_ids
}
body_source_ids = {
claim["claim_key"]: _independent_planned_uuid(parent_id, "claim-body-source", claim["claim_key"])
for claim in claims
}
evidence_rows: list[dict[str, Any]] = []
seen_evidence: set[tuple[str, str, str]] = set()
def append_evidence(claim_id: str, source_id: str, role: str) -> None:
key = (claim_id, source_id, role)
if key in seen_evidence:
return
seen_evidence.add(key)
evidence_rows.append(
{
"claim_id": claim_id,
"source_id": source_id,
"role": role,
"weight": None,
"created_by": None,
}
)
for claim in claims:
claim_key = claim["claim_key"]
claim_id = claim_ids[claim_key]
append_evidence(claim_id, body_source_ids[claim_key], "illustrates")
for evidence in claim["evidence"]:
append_evidence(claim_id, segment_source_ids[evidence["segment_id"]], evidence["role"])
edge_rows: list[dict[str, Any]] = []
seen_edges: set[tuple[str, str, str]] = set()
for claim in claims:
from_claim = claim_ids[claim["claim_key"]]
for edge in claim["edges"]:
target_key = _require_text(edge.get("target"), f"claim {claim['claim_key']} edge target")
to_claim = claim_ids.get(target_key)
if to_claim is None:
raise CanaryError(f"claim {claim['claim_key']} edge references unknown claim {target_key}")
edge_type = _require_text(edge.get("edge_type"), f"claim {claim['claim_key']} edge type")
identity = (from_claim, to_claim, edge_type)
if identity in seen_edges:
continue
seen_edges.add(identity)
edge_rows.append(
{
"from_claim": from_claim,
"to_claim": to_claim,
"edge_type": edge_type,
"weight": edge.get("weight"),
"created_by": None,
}
)
return {
"planned_claim_ids": [claim_ids[claim["claim_key"]] for claim in claims],
"planned_source_ids": [
*(segment_source_ids[segment_id] for segment_id in referenced_segment_ids),
*(body_source_ids[claim["claim_key"]] for claim in claims),
],
"planned_evidence_rows": evidence_rows,
"planned_edge_rows": edge_rows,
}
def build_schema_sql() -> str:
return rf"""\set ON_ERROR_STOP on
create schema kb_canary;
create schema kb_stage;
create table public.claims (
id uuid primary key, type text not null, text text not null, status text not null,
confidence double precision, tags text[] not null default '{{}}'
);
create table public.sources (
id uuid primary key, source_type text not null, url text, storage_path text,
excerpt text, hash text not null
);
create table public.claim_evidence (
claim_id uuid not null, source_id uuid not null, role text not null, weight double precision,
primary key (claim_id, source_id, role)
);
create table public.claim_edges (
from_claim uuid not null, to_claim uuid not null, edge_type text not null, weight double precision,
primary key (from_claim, to_claim, edge_type)
);
insert into public.claims(id, type, text, status, confidence, tags) values
('{SEED_CLAIM_A}', 'structural', 'A staged proposal is non-canonical until guarded apply succeeds.', 'open', 0.99, array['seed']),
('{SEED_CLAIM_B}', 'meta', 'Review and canonical application are separate state transitions.', 'open', 0.98, array['seed']);
insert into public.sources(id, source_type, storage_path, excerpt, hash) values
('{SEED_SOURCE}', 'observation', 'fixture://canonical/seed', 'Representative canonical seed.',
'{"a" * 64}');
insert into public.claim_evidence(claim_id, source_id, role, weight) values
('{SEED_CLAIM_A}', '{SEED_SOURCE}', 'grounds', 1.0);
insert into public.claim_edges(from_claim, to_claim, edge_type, weight) values
('{SEED_CLAIM_A}', '{SEED_CLAIM_B}', 'supports', 1.0);
create table kb_canary.source_captures (
id uuid primary key,
source_identity text not null unique,
source_type text not null,
title text not null,
locator text not null,
artifact_path text not null,
artifact_sha256 text not null check (artifact_sha256 ~ '^[0-9a-f]{{64}}$'),
content_sha256 text not null check (content_sha256 ~ '^[0-9a-f]{{64}}$'),
replay_identity_sha256 text not null check (replay_identity_sha256 ~ '^[0-9a-f]{{64}}$'),
metadata jsonb not null
);
create table kb_canary.claim_extractions (
id uuid primary key,
source_capture_id uuid not null references kb_canary.source_captures(id),
claim_key text not null unique,
body text not null,
metadata jsonb not null
);
create table kb_canary.evidence_extractions (
id uuid primary key,
claim_extraction_id uuid not null references kb_canary.claim_extractions(id),
source_capture_id uuid not null references kb_canary.source_captures(id),
source_segment_id text not null,
source_locator text not null,
source_json_pointer text,
role text not null,
body text not null,
body_sha256 text not null,
source_content_sha256 text not null,
metadata jsonb not null
);
create table kb_canary.duplicate_assessments (
id uuid primary key,
source_capture_id uuid not null references kb_canary.source_captures(id),
source_segment_id text not null,
source_locator text not null,
duplicate_of_claim_key text not null,
excerpt text not null,
excerpt_sha256 text not null,
reason text not null,
metadata jsonb not null
);
create table kb_canary.conflict_assessments (
id uuid primary key,
source_capture_id uuid not null references kb_canary.source_captures(id),
from_claim_key text not null,
to_claim_key text not null,
relationship text not null,
metadata jsonb not null
);
create table kb_stage.kb_proposals (
id uuid primary key,
proposal_type text not null,
status text not null,
proposed_by_handle text,
proposed_by_agent_id uuid,
channel text not null,
source_ref text not null,
rationale text not null,
payload jsonb not null,
reviewed_by_handle text,
reviewed_by_agent_id uuid,
reviewed_at timestamptz,
review_note text,
applied_by_handle text,
applied_by_agent_id uuid,
applied_at timestamptz
);
"""
def build_canonical_snapshot_sql() -> str:
return r"""\set ON_ERROR_STOP on
begin transaction read only;
select jsonb_build_object(
'claims', coalesce((select jsonb_agg(to_jsonb(t) order by t.id) from public.claims t), '[]'::jsonb),
'sources', coalesce((select jsonb_agg(to_jsonb(t) order by t.id) from public.sources t), '[]'::jsonb),
'claim_evidence', coalesce((select jsonb_agg(to_jsonb(t) order by t.claim_id, t.source_id, t.role)
from public.claim_evidence t), '[]'::jsonb),
'claim_edges', coalesce((select jsonb_agg(to_jsonb(t) order by t.from_claim, t.to_claim, t.edge_type)
from public.claim_edges t), '[]'::jsonb)
)::text;
rollback;
"""
def expected_persisted_rows(
fixture: dict[str, Any], input_receipt: dict[str, Any], row_ids: dict[str, Any]
) -> dict[str, list[dict[str, Any]]]:
"""Project the complete relational identity expected from one fixture."""
source = fixture["source"]
expected: dict[str, list[dict[str, Any]]] = {
"source_captures": [
{
"id": row_ids["source_capture_id"],
"source_identity": source["identity"],
"source_type": source["source_type"],
"title": source["title"],
"locator": source["locator"],
"artifact_path": input_receipt["artifact_path"],
"artifact_sha256": input_receipt["artifact_sha256"],
"content_sha256": input_receipt["source_content_sha256"],
"replay_identity_sha256": input_receipt["replay_identity_sha256"],
"metadata": {**source["metadata"], "extractor": input_receipt["extractor"]},
}
],
"claim_extractions": [],
"evidence_extractions": [],
"duplicate_assessments": [],
"conflict_assessments": [],
}
segment_by_id = {segment["id"]: segment for segment in fixture["segments"]}
for claim in fixture["extraction"]["claims"]:
claim_id = row_ids["claim_extraction_ids"][claim["claim_key"]]
expected["claim_extractions"].append(
{
"id": claim_id,
"source_capture_id": row_ids["source_capture_id"],
"claim_key": claim["claim_key"],
"body": claim["body"],
"metadata": {
**claim["metadata"],
"claim_type": claim["type"],
"confidence": claim["confidence"],
"text": claim["text"],
"extractor": input_receipt["extractor"],
"replay_identity_sha256": input_receipt["replay_identity_sha256"],
},
}
)
for index, evidence in enumerate(claim["evidence"]):
evidence_key = f"{claim['claim_key']}:{index}"
segment = segment_by_id[evidence["segment_id"]]
expected["evidence_extractions"].append(
{
"id": row_ids["evidence_extraction_ids"][evidence_key],
"claim_extraction_id": claim_id,
"source_capture_id": row_ids["source_capture_id"],
"source_segment_id": segment["id"],
"source_locator": segment["locator"],
"source_json_pointer": segment["json_pointer"],
"role": evidence["role"],
"body": evidence["excerpt"],
"body_sha256": sha256_bytes(evidence["excerpt"].encode()),
"source_content_sha256": segment["content_sha256"],
"metadata": {
**_require_object(evidence.get("metadata", {}), f"evidence {evidence_key}.metadata"),
"source_text_sha256": segment["text_sha256"],
},
}
)
for index, duplicate in enumerate(fixture["extraction"]["duplicates"]):
expected["duplicate_assessments"].append(
{
"id": row_ids["duplicate_assessment_ids"][str(index)],
"source_capture_id": row_ids["source_capture_id"],
"source_segment_id": duplicate["segment_id"],
"source_locator": duplicate["source_locator"],
"duplicate_of_claim_key": duplicate["duplicate_of_claim_key"],
"excerpt": duplicate["excerpt"],
"excerpt_sha256": sha256_bytes(duplicate["excerpt"].encode()),
"reason": duplicate["reason"],
"metadata": {
"json_pointer": duplicate["source_json_pointer"],
"source_content_sha256": duplicate["source_content_sha256"],
"source_text_sha256": duplicate["source_text_sha256"],
},
}
)
for index, conflict in enumerate(fixture["extraction"]["conflicts"]):
expected["conflict_assessments"].append(
{
"id": row_ids["conflict_assessment_ids"][str(index)],
"source_capture_id": row_ids["source_capture_id"],
"from_claim_key": conflict["from_claim_key"],
"to_claim_key": conflict["to_claim_key"],
"relationship": conflict["relationship"],
"metadata": {
key: value
for key, value in conflict.items()
if key not in {"from_claim_key", "to_claim_key", "relationship"}
},
}
)
return expected
def rows_exact(actual: Any, expected: list[dict[str, Any]]) -> bool:
"""Compare complete row identities independent of database result order."""
return (
isinstance(actual, list)
and all(isinstance(row, dict) for row in actual)
and sorted(actual, key=canonical_json_bytes) == sorted(expected, key=canonical_json_bytes)
)
def build_capture_sql(fixture: dict[str, Any], input_receipt: dict[str, Any], row_ids: dict[str, Any]) -> str:
source = fixture["source"]
q = ap.sql_literal
statements = [
r"\set ON_ERROR_STOP on",
"begin;",
"insert into kb_canary.source_captures "
"(id, source_identity, source_type, title, locator, artifact_path, artifact_sha256, content_sha256, "
"replay_identity_sha256, metadata) values "
f"({q(row_ids['source_capture_id'])}::uuid, {q(source['identity'])}, {q(source['source_type'])}, "
f"{q(source['title'])}, {q(source['locator'])}, {q(input_receipt['artifact_path'])}, "
f"{q(input_receipt['artifact_sha256'])}, {q(input_receipt['source_content_sha256'])}, "
f"{q(input_receipt['replay_identity_sha256'])}, "
f"{q(json.dumps({**source['metadata'], 'extractor': input_receipt['extractor']}, sort_keys=True))}::jsonb);",
]
segment_by_id = {segment["id"]: segment for segment in fixture["segments"]}
for claim in fixture["extraction"]["claims"]:
claim_id = row_ids["claim_extraction_ids"][claim["claim_key"]]
claim_metadata = {
**claim["metadata"],
"claim_type": claim["type"],
"confidence": claim["confidence"],
"text": claim["text"],
"extractor": input_receipt["extractor"],
"replay_identity_sha256": input_receipt["replay_identity_sha256"],
}
statements.append(
"insert into kb_canary.claim_extractions "
"(id, source_capture_id, claim_key, body, metadata) values "
f"({q(claim_id)}::uuid, {q(row_ids['source_capture_id'])}::uuid, {q(claim['claim_key'])}, "
f"{q(claim['body'])}, {q(json.dumps(claim_metadata, sort_keys=True))}::jsonb);"
)
for index, evidence in enumerate(claim["evidence"]):
evidence_key = f"{claim['claim_key']}:{index}"
segment = segment_by_id[evidence["segment_id"]]
evidence_metadata = {
**_require_object(evidence.get("metadata", {}), f"evidence {evidence_key}.metadata"),
"source_text_sha256": segment["text_sha256"],
}
statements.append(
"insert into kb_canary.evidence_extractions "
"(id, claim_extraction_id, source_capture_id, source_segment_id, source_locator, "
"source_json_pointer, role, body, body_sha256, source_content_sha256, metadata) values "
f"({q(row_ids['evidence_extraction_ids'][evidence_key])}::uuid, {q(claim_id)}::uuid, "
f"{q(row_ids['source_capture_id'])}::uuid, {q(segment['id'])}, {q(segment['locator'])}, "
f"{q(segment['json_pointer'])}, {q(evidence['role'])}, {q(evidence['excerpt'])}, "
f"{q(sha256_bytes(evidence['excerpt'].encode()))}, {q(segment['content_sha256'])}, "
f"{q(json.dumps(evidence_metadata, sort_keys=True))}::jsonb);"
)
for index, duplicate in enumerate(fixture["extraction"]["duplicates"]):
statements.append(
"insert into kb_canary.duplicate_assessments "
"(id, source_capture_id, source_segment_id, source_locator, duplicate_of_claim_key, excerpt, "
"excerpt_sha256, reason, metadata) values "
f"({q(row_ids['duplicate_assessment_ids'][str(index)])}::uuid, "
f"{q(row_ids['source_capture_id'])}::uuid, {q(duplicate['segment_id'])}, "
f"{q(duplicate['source_locator'])}, {q(duplicate['duplicate_of_claim_key'])}, "
f"{q(duplicate['excerpt'])}, {q(sha256_bytes(duplicate['excerpt'].encode()))}, "
f"{q(duplicate['reason'])}, {q(json.dumps({'json_pointer': duplicate['source_json_pointer'], 'source_content_sha256': duplicate['source_content_sha256'], 'source_text_sha256': duplicate['source_text_sha256']}, sort_keys=True))}::jsonb);"
)
for index, conflict in enumerate(fixture["extraction"]["conflicts"]):
statements.append(
"insert into kb_canary.conflict_assessments "
"(id, source_capture_id, from_claim_key, to_claim_key, relationship, metadata) values "
f"({q(row_ids['conflict_assessment_ids'][str(index)])}::uuid, "
f"{q(row_ids['source_capture_id'])}::uuid, {q(conflict['from_claim_key'])}, "
f"{q(conflict['to_claim_key'])}, {q(conflict['relationship'])}, "
f"{q(json.dumps({key: value for key, value in conflict.items() if key not in {'from_claim_key', 'to_claim_key', 'relationship'}}, sort_keys=True))}::jsonb);"
)
statements.append("commit;")
return "\n".join(statements) + "\n"
def build_readback_sql(proposal_id: str) -> str:
q = ap.sql_literal
return rf"""\set ON_ERROR_STOP on
begin transaction read only;
select jsonb_build_object(
'source_captures', coalesce((select jsonb_agg(to_jsonb(t) order by t.id) from kb_canary.source_captures t), '[]'::jsonb),
'claim_extractions', coalesce((select jsonb_agg(to_jsonb(t) order by t.claim_key) from kb_canary.claim_extractions t), '[]'::jsonb),
'evidence_extractions', coalesce((select jsonb_agg(to_jsonb(t) order by t.id) from kb_canary.evidence_extractions t), '[]'::jsonb),
'duplicate_assessments', coalesce((select jsonb_agg(to_jsonb(t) order by t.id) from kb_canary.duplicate_assessments t), '[]'::jsonb),
'conflict_assessments', coalesce((select jsonb_agg(to_jsonb(t) order by t.id) from kb_canary.conflict_assessments t), '[]'::jsonb),
'staged_proposal', (select to_jsonb(p) from kb_stage.kb_proposals p where id = {q(proposal_id)}::uuid),
'counts', jsonb_build_object(
'source_captures', (select count(*) from kb_canary.source_captures),
'claim_extractions', (select count(*) from kb_canary.claim_extractions),
'evidence_extractions', (select count(*) from kb_canary.evidence_extractions),
'duplicate_assessments', (select count(*) from kb_canary.duplicate_assessments),
'conflict_assessments', (select count(*) from kb_canary.conflict_assessments),
'staged_proposals', (select count(*) from kb_stage.kb_proposals)
)
)::text;
rollback;
"""
class DockerPostgres:
def __init__(self, name: str) -> None:
self.name = name
self.docker = shutil.which("docker")
if not self.docker:
raise CanaryError("docker executable is unavailable")
self.started = False
self.volume_mounts: list[dict[str, Any]] = []
def _run(
self, args: list[str], *, input_text: str | None = None, check: bool = True
) -> subprocess.CompletedProcess[str]:
result = subprocess.run([self.docker, *args], input=input_text, text=True, capture_output=True, check=False)
if check and result.returncode != 0:
detail = (result.stderr or result.stdout).strip()
raise CanaryError(f"docker {' '.join(args[:3])} failed ({result.returncode}): {detail}")
return result
def start(self) -> dict[str, Any]:
result = self._run(
[
"run",
"--rm",
"-d",
"--name",
self.name,
"--network",
"none",
"--label",
CONTAINER_LABEL,
"--tmpfs",
"/var/lib/postgresql/data:rw,nosuid,size=256m",
"-e",
"POSTGRES_HOST_AUTH_METHOD=trust",
"-e",
"POSTGRES_DB=teleo",
"postgres:16-alpine",
]
)
self.started = True
container_id = result.stdout.strip()
deadline = time.monotonic() + 30
ready_streak = 0
while time.monotonic() < deadline:
ready = self._run(["exec", self.name, "pg_isready", "-U", "postgres", "-d", "teleo"], check=False)
if ready.returncode == 0:
ready_streak += 1
if ready_streak >= 2:
break
else:
ready_streak = 0
time.sleep(0.25)
else:
raise CanaryError("disposable Postgres did not become ready within 30 seconds")
inspect = json.loads(self._run(["inspect", self.name]).stdout)[0]
if inspect["HostConfig"]["NetworkMode"] != "none":
raise CanaryError("disposable Postgres must use network mode none")
if inspect["Config"]["Labels"].get("livingip.canary") != "working-leo-local-ingestion":
raise CanaryError("disposable Postgres is missing its canary label")
self.volume_mounts = [
{"type": mount.get("Type"), "name": mount.get("Name"), "destination": mount.get("Destination")}
for mount in inspect.get("Mounts", [])
if mount.get("Type") == "volume"
]
if self.volume_mounts:
raise CanaryError("disposable Postgres unexpectedly created a Docker volume")
return {
"container_id": container_id,
"name": self.name,
"image": inspect["Config"]["Image"],
"network_mode": inspect["HostConfig"]["NetworkMode"],
"tmpfs_data_dir": "/var/lib/postgresql/data" in inspect["HostConfig"].get("Tmpfs", {}),
"docker_volume_mounts": self.volume_mounts,
"canary_label": inspect["Config"]["Labels"].get("livingip.canary"),
}
def psql(self, sql: str) -> str:
result = self._run(
["exec", "-i", self.name, "psql", "-U", "postgres", "-d", "teleo", "-Atq"],
input_text=sql,
)
return result.stdout.strip()
def psql_json(self, sql: str) -> dict[str, Any]:
output = self.psql(sql)
lines = [line for line in output.splitlines() if line.strip()]
if not lines:
raise CanaryError("Postgres readback returned no JSON")
try:
value = json.loads(lines[-1])
except json.JSONDecodeError as exc:
raise CanaryError(f"Postgres readback was not JSON: {lines[-1]}") from exc
if not isinstance(value, dict):
raise CanaryError("Postgres readback must be a JSON object")
return value
def cleanup(self) -> dict[str, Any]:
remove = self._run(["rm", "-f", self.name], check=False) if self.started else None
inspect = self._run(["inspect", self.name], check=False)
return {
"remove_attempted": self.started,
"remove_returncode": remove.returncode if remove else None,
"container_absent": inspect.returncode != 0,
"docker_volume_mounts_observed": self.volume_mounts,
"anonymous_or_named_volume_created": bool(self.volume_mounts),
}
def proposal_readback_parts(
readback: dict[str, Any],
) -> tuple[dict[str, Any], dict[str, Any], dict[str, Any], dict[str, Any], dict[str, Any]]:
"""Extract typed proposal layers so every verifier path fails closed consistently."""
proposal_value = readback.get("staged_proposal")
proposal = proposal_value if isinstance(proposal_value, dict) else {}
payload_value = proposal.get("payload")
payload = payload_value if isinstance(payload_value, dict) else {}
apply_value = payload.get("apply_payload")
apply_payload = apply_value if isinstance(apply_value, dict) else {}
manifest_value = apply_payload.get("normalization_manifest")
manifest = manifest_value if isinstance(manifest_value, dict) else {}
ingestion_value = manifest.get("ingestion_manifest")
ingestion_manifest = ingestion_value if isinstance(ingestion_value, dict) else {}
assessment_value = manifest.get("dedupe_conflict_assessment")
assessment = assessment_value if isinstance(assessment_value, dict) else {}
return proposal, apply_payload, manifest, ingestion_manifest, assessment
def proposal_links(readback: dict[str, Any]) -> dict[str, Any]:
"""Project observed proposal row identities and links without judging them."""
proposal, apply_payload, _manifest, ingestion_manifest, _assessment = proposal_readback_parts(readback)
claim_rows = apply_payload.get("claims") if isinstance(apply_payload.get("claims"), list) else []
source_rows = apply_payload.get("sources") if isinstance(apply_payload.get("sources"), list) else []
evidence_rows = apply_payload.get("evidence") if isinstance(apply_payload.get("evidence"), list) else []
edge_rows = apply_payload.get("edges") if isinstance(apply_payload.get("edges"), list) else []
planned_evidence_rows = [
{
"claim_id": row.get("claim_id"),
"source_id": row.get("source_id"),
"role": row.get("role"),
"weight": row.get("weight"),
"created_by": row.get("created_by"),
}
for row in evidence_rows
if isinstance(row, dict)
]
planned_edge_rows = [
{
"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"),
}
for row in edge_rows
if isinstance(row, dict)
]
return {
"proposal_id": proposal.get("id"),
"proposal_status": proposal.get("status"),
"proposal_source_ref": proposal.get("source_ref"),
"planned_claim_ids": [row.get("id") for row in claim_rows if isinstance(row, dict)],
"planned_source_ids": [row.get("id") for row in source_rows if isinstance(row, dict)],
"planned_evidence_keys": [
{key: row[key] for key in ("claim_id", "source_id", "role")} for row in planned_evidence_rows
],
"planned_edge_keys": [
{key: row[key] for key in ("from_claim", "to_claim", "edge_type")} for row in planned_edge_rows
],
"planned_evidence_rows": planned_evidence_rows,
"planned_edge_rows": planned_edge_rows,
"planned_counts": {
"claims": len(claim_rows),
"sources": len(source_rows),
"evidence": len(evidence_rows),
"edges": len(edge_rows),
},
"manifest_artifact_sha256": ingestion_manifest.get("artifact_sha256"),
"manifest_replay_identity_sha256": ingestion_manifest.get("replay_identity_sha256"),
"manifest_row_ids": ingestion_manifest.get("row_ids"),
}
def proposal_link_proof(readback: dict[str, Any], input_receipt: dict[str, Any]) -> dict[str, Any]:
"""Attach explicit comparisons to the pure observed link projection for receipts."""
links = proposal_links(readback)
return {
**links,
"input_hash_in_manifest": links["manifest_artifact_sha256"] == input_receipt["artifact_sha256"],
"replay_identity_in_manifest": (
links["manifest_replay_identity_sha256"] == input_receipt["replay_identity_sha256"]
),
}
def evaluate_checks(
fixture: dict[str, Any],
input_receipt: dict[str, Any],
row_ids: dict[str, Any],
readback: dict[str, Any],
canonical_before: dict[str, Any],
canonical_after: dict[str, Any],
) -> dict[str, bool]:
source_value = readback.get("source_captures")
claim_value = readback.get("claim_extractions")
evidence_value = readback.get("evidence_extractions")
duplicate_value = readback.get("duplicate_assessments")
conflict_value = readback.get("conflict_assessments")
source_rows = source_value if isinstance(source_value, list) else []
claim_rows = claim_value if isinstance(claim_value, list) else []
evidence_rows = evidence_value if isinstance(evidence_value, list) else []
duplicate_rows = duplicate_value if isinstance(duplicate_value, list) else []
conflict_rows = conflict_value if isinstance(conflict_value, list) else []
proposal, apply_payload, _manifest, ingestion_manifest, assessment = proposal_readback_parts(readback)
counts = input_receipt["counts"]
links = proposal_links(readback)
deterministic_row_ids = build_row_ids(input_receipt, fixture)
expected_rows = expected_persisted_rows(fixture, input_receipt, deterministic_row_ids)
expected_parent = build_parent_packet(fixture, input_receipt, deterministic_row_ids)
expected_child = normalized_stage.prepare_normalized_child(expected_parent)
expected_apply_payload = expected_child["payload"]["apply_payload"]
persisted_proposal_envelope_fields = (
"id",
"proposal_type",
"status",
"proposed_by_handle",
"proposed_by_agent_id",
"channel",
"source_ref",
"rationale",
"reviewed_by_handle",
"reviewed_by_agent_id",
"reviewed_at",
"review_note",
"applied_by_handle",
"applied_by_agent_id",
"applied_at",
)
expected_proposal_envelope = {key: expected_child.get(key) for key in persisted_proposal_envelope_fields}
actual_proposal_envelope = {key: proposal.get(key) for key in persisted_proposal_envelope_fields}
expected_db_counts = {
"source_captures": 1,
"claim_extractions": counts["claim_candidates"],
"evidence_extractions": counts["evidence_candidates"],
"duplicate_assessments": counts["duplicate_judgments"],
"conflict_assessments": counts["conflict_relationships"],
"staged_proposals": 1,
}
source_rows_exact = rows_exact(source_rows, expected_rows["source_captures"])
claim_rows_exact = rows_exact(claim_rows, expected_rows["claim_extractions"])
evidence_rows_exact = rows_exact(evidence_rows, expected_rows["evidence_extractions"])
duplicate_rows_exact = rows_exact(duplicate_rows, expected_rows["duplicate_assessments"])
conflict_rows_exact = rows_exact(conflict_rows, expected_rows["conflict_assessments"])
proposal_envelope_exact = actual_proposal_envelope == expected_proposal_envelope
planned_rows_exact = all(
apply_payload.get(collection) == expected_apply_payload.get(collection)
for collection in ("claims", "sources", "evidence", "edges")
)
graph_collections = {"claims", "sources", "evidence", "edges"}
apply_auxiliary_exact = {key: value for key, value in apply_payload.items() if key not in graph_collections} == {
key: value for key, value in expected_apply_payload.items() if key not in graph_collections
}
expected_graph_identity = expected_planned_graph_identity(fixture, deterministic_row_ids)
actual_graph_identity = {
key: links[key]
for key in ("planned_claim_ids", "planned_source_ids", "planned_evidence_rows", "planned_edge_rows")
}
independent_graph_identity_exact = actual_graph_identity == expected_graph_identity
pending_state = normalized_stage.bound._state_semantics(proposal, "pending_review")
source_row = source_rows[0] if len(source_rows) == 1 and isinstance(source_rows[0], dict) else {}
claim_rows_are_objects = all(isinstance(row, dict) for row in claim_rows)
return {
"source_only_artifact_hash_persisted": (
len(source_rows) == 1 and source_row.get("artifact_sha256") == input_receipt["artifact_sha256"]
),
"source_capture_identity_exact": source_rows_exact,
"deterministic_row_ids_recomputed_exact": row_ids == deterministic_row_ids,
"replay_identity_persisted": (
len(source_rows) == 1
and source_row.get("replay_identity_sha256") == input_receipt["replay_identity_sha256"]
),
"extractor_name_and_version_persisted": (
ingestion_manifest.get("extractor") == input_receipt["extractor"]
and claim_rows_are_objects
and all(
isinstance(row.get("metadata"), dict) and row["metadata"].get("extractor") == input_receipt["extractor"]
for row in claim_rows
)
),
"all_claim_candidates_persisted_once": (
claim_rows_are_objects
and {row.get("claim_key") for row in claim_rows}
== {claim["claim_key"] for claim in fixture["extraction"]["claims"]}
and len(claim_rows) == counts["claim_candidates"]
),
"claim_extraction_identities_and_fks_exact": claim_rows_exact,
"all_evidence_has_exact_source_location": (
len(evidence_rows) == counts["evidence_candidates"] and evidence_rows_exact
),
"evidence_extraction_identities_and_fks_exact": evidence_rows_exact,
"duplicate_judgments_persisted": (
len(duplicate_rows) == counts["duplicate_judgments"]
and duplicate_rows_exact
and assessment.get("duplicates") == fixture["extraction"]["duplicates"]
),
"conflicts_and_relationships_persisted": (
len(conflict_rows) == counts["conflict_relationships"]
and conflict_rows_exact
and assessment.get("conflicts") == fixture["extraction"]["conflicts"]
and links["planned_edge_rows"] == expected_graph_identity["planned_edge_rows"]
),
"planned_graph_matches_independent_source_oracle": independent_graph_identity_exact,
"planned_proposal_identities_and_linkages_exact": (
proposal_envelope_exact
and planned_rows_exact
and apply_auxiliary_exact
and independent_graph_identity_exact
and links["manifest_row_ids"] == deterministic_row_ids
and links["proposal_id"] == expected_child["id"]
and links["proposal_status"] == expected_child["status"]
and links["proposal_source_ref"] == expected_child["source_ref"]
),
"database_candidate_counts_exact": readback.get("counts") == expected_db_counts,
"proposal_is_pending_review": pending_state["status_matches"],
"proposal_has_replayable_ingestion_manifest": (
links["manifest_artifact_sha256"] == input_receipt["artifact_sha256"]
and links["manifest_replay_identity_sha256"] == input_receipt["replay_identity_sha256"]
and ingestion_manifest == expected_apply_payload["normalization_manifest"]["ingestion_manifest"]
),
"no_review_or_apply_metadata": (
pending_state["review_fields_match"]
and pending_state["apply_fields_match"]
and proposal.get("review_note") is None
),
"canonical_snapshot_nonempty": (
canonical_snapshot_complete(canonical_before) and canonical_snapshot_complete(canonical_after)
),
"canonical_fingerprint_unchanged": (
canonical_snapshot_complete(canonical_before)
and canonical_snapshot_complete(canonical_after)
and canonical_sha256(canonical_before) == canonical_sha256(canonical_after)
),
}
def run_canary(fixture_path: Path, output: Path | None = None) -> dict[str, Any]:
receipt: dict[str, Any] = {
"schema": SCHEMA,
"status": "fail",
"required_tier": "T2_runtime_to_review_queue_staging",
"input": {"scenario_path": str(fixture_path.resolve())},
"row_ids": {},
"production_mutation_attempted": False,
"canonical_apply_attempted": False,
}
postgres: DockerPostgres | None = None
try:
fixture, input_receipt = load_fixture(fixture_path)
row_ids = build_row_ids(input_receipt, fixture)
parent = build_parent_packet(fixture, input_receipt, row_ids)
child = normalized_stage.prepare_normalized_child(parent)
receipt["input"] = input_receipt
receipt["row_ids"] = row_ids
postgres = DockerPostgres(f"working-leo-ingest-{uuid.uuid4().hex[:12]}")
receipt["environment"] = postgres.start()
postgres.psql(build_schema_sql())
canonical_before = postgres.psql_json(build_canonical_snapshot_sql())
postgres.psql(build_capture_sql(fixture, input_receipt, row_ids))
stage_result = postgres.psql_json(normalized_stage.build_stage_sql(child))
readback = postgres.psql_json(build_readback_sql(child["id"]))
canonical_after = postgres.psql_json(build_canonical_snapshot_sql())
canonical_unchanged = (
canonical_snapshot_complete(canonical_before)
and canonical_snapshot_complete(canonical_after)
and canonical_sha256(canonical_before) == canonical_sha256(canonical_after)
)
checks = evaluate_checks(fixture, input_receipt, row_ids, readback, canonical_before, canonical_after)
receipt.update(
{
"stage_command_result": stage_result,
"rows": readback,
"candidate_counts": input_receipt["counts"],
"row_link_fields_proven": proposal_link_proof(readback, input_receipt),
"canonical": {
"fingerprint_before": canonical_sha256(canonical_before),
"fingerprint_after": canonical_sha256(canonical_after),
"table_counts": {key: len(canonical_before[key]) for key in CANONICAL_TABLES},
"unchanged": canonical_unchanged,
},
"checks": checks,
"status": "pass" if all(checks.values()) else "fail",
}
)
except (
CanaryError,
OSError,
ValueError,
KeyError,
TypeError,
AttributeError,
IndexError,
normalized_stage.bound.CheckpointError,
) as exc:
receipt["error"] = {"type": type(exc).__name__, "message": str(exc)}
finally:
if postgres is None:
receipt["cleanup"] = {
"remove_attempted": False,
"remove_returncode": None,
"container_absent": True,
"docker_volume_mounts_observed": [],
"anonymous_or_named_volume_created": False,
"runtime_not_started": True,
"network_mode_none": True,
}
else:
receipt["cleanup"] = postgres.cleanup()
receipt["cleanup"]["runtime_not_started"] = not postgres.started
receipt["cleanup"]["network_mode_none"] = receipt.get("environment", {}).get("network_mode") == "none"
receipt["cleanup"]["no_production_target_referenced"] = receipt["cleanup"]["network_mode_none"]
if not all((receipt["cleanup"]["container_absent"], receipt["cleanup"]["network_mode_none"])):
receipt["status"] = "fail"
if receipt["status"] == "pass":
receipt["strongest_claim"] = (
"One source-only artifact was parsed into exact-location candidate claims, duplicate/conflict "
"assessments, and a replay-bound pending_review proposal in disposable networkless Postgres; "
"representative canonical row contents remained fingerprint-identical."
)
else:
receipt["strongest_claim"] = (
"No source-to-review-staging capability claim is made because acceptance failed closed."
)
receipt["residual_gap"] = (
"This proves the deterministic local fixture extractor and review queue only; it does not prove "
"arbitrary generative extraction, approval/apply, hosted runtime, or production mutation."
)
if output:
output.parent.mkdir(parents=True, exist_ok=True)
output.write_text(json.dumps(receipt, indent=2, sort_keys=True) + "\n", encoding="utf-8")
return receipt
def receipt_proves_canonical_invariance(receipt: dict[str, Any]) -> bool:
"""Recompute the suite-level canonical verdict from receipt evidence."""
canonical = receipt.get("canonical")
checks = receipt.get("checks")
if not isinstance(canonical, dict) or not isinstance(checks, dict):
return False
before = canonical.get("fingerprint_before")
after = canonical.get("fingerprint_after")
return (
isinstance(before, str)
and isinstance(after, str)
and re.fullmatch(r"[0-9a-f]{64}", before) is not None
and re.fullmatch(r"[0-9a-f]{64}", after) is not None
and before == after
and canonical.get("unchanged") is True
and checks.get("canonical_fingerprint_unchanged") is True
)
def run_suite(fixture_paths: list[Path], output: Path | None = None) -> dict[str, Any]:
receipts = [run_canary(path.resolve()) for path in fixture_paths]
all_supplied_pass = bool(receipts) and all(item.get("status") == "pass" for item in receipts)
document_fixture_passed = any(
item.get("status") == "pass" and item.get("input", {}).get("artifact_format") == "plain_text"
for item in receipts
)
social_conversation_fixture_passed = any(
item.get("status") == "pass" and item.get("input", {}).get("artifact_format") == "telegram_jsonl"
for item in receipts
)
canonical_fingerprint_invariant_all = bool(receipts) and all(
receipt_proves_canonical_invariance(item) for item in receipts
)
required_shape_coverage = document_fixture_passed and social_conversation_fixture_passed
full_suite_passed = all_supplied_pass and required_shape_coverage and canonical_fingerprint_invariant_all
if not all_supplied_pass or not canonical_fingerprint_invariant_all:
status = "fail"
elif full_suite_passed:
status = "pass"
else:
status = "partial"
missing_required_coverage = []
if not document_fixture_passed:
missing_required_coverage.append("document")
if not social_conversation_fixture_passed:
missing_required_coverage.append("social_conversation")
if not canonical_fingerprint_invariant_all:
missing_required_coverage.append("canonical_fingerprint_invariance")
suite = {
"schema": SUITE_SCHEMA,
"status": status,
"required_tier": "T2_runtime_to_review_queue_staging",
"current_tier": (
"T2_runtime_to_review_queue_staging"
if full_suite_passed
else "T2_runtime_single_fixture"
if status == "partial"
else "runtime_verification_failed"
),
"fixture_count": len(receipts),
"all_supplied_fixtures_passed": all_supplied_pass,
"document_fixture_passed": document_fixture_passed,
"social_conversation_fixture_passed": social_conversation_fixture_passed,
"canonical_fingerprint_invariant_all": canonical_fingerprint_invariant_all,
"required_shape_coverage_met": required_shape_coverage,
"coverage_status": "full" if required_shape_coverage else "partial",
"missing_required_coverage": missing_required_coverage,
"full_suite_passed": full_suite_passed,
"receipts": receipts,
}
if output:
output.parent.mkdir(parents=True, exist_ok=True)
output.write_text(json.dumps(suite, indent=2, sort_keys=True) + "\n", encoding="utf-8")
return suite
def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
"--fixture",
type=Path,
action="append",
help="repeatable scenario path; defaults to the document and Telegram scenarios",
)
parser.add_argument("--output", type=Path)
return parser.parse_args(argv)
def main(argv: list[str] | None = None) -> int:
args = parse_args(argv)
fixtures = args.fixture or list(DEFAULT_FIXTURES)
receipt = run_suite([path.resolve() for path in fixtures], args.output.resolve() if args.output else None)
print(json.dumps(receipt, sort_keys=True, separators=(",", ":")))
return 0 if receipt["status"] == "pass" else 1
if __name__ == "__main__":
raise SystemExit(main())