teleo-infrastructure/scripts/run_leo_clone_composition_checkpoint.py

1093 lines
54 KiB
Python

#!/usr/bin/env python3
"""Prove Leo can compose and reason over source-derived KB rows in a disposable clone."""
from __future__ import annotations
import argparse
import asyncio
import hashlib
import json
import sys
import traceback
import uuid
from pathlib import Path
from types import SimpleNamespace
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 run_approve_claim_clone_canary as guarded # noqa: E402
import run_leo_clone_bound_handler_checkpoint as bound # noqa: E402
import run_leo_clone_lifecycle_checkpoint as lifecycle # noqa: E402
import stage_normalized_proposal as normalized_stage # noqa: E402
SCHEMA = "livingip.leoCloneCompositionCheckpoint.v1"
PACKET_PREFIX = "COMPOSITION_PACKET:"
STATE_PREFIX = "COMPOSITION_STATE:"
TABLES = lifecycle.LIFECYCLE_TABLES
PRODUCTION_TABLES = bound.COUNT_TABLES
def _stable_uuid(run_marker: str, label: str) -> str:
return str(uuid.uuid5(uuid.NAMESPACE_URL, f"livingip:leo-composition:{run_marker}:{label}"))
def build_source_fixture(run_marker: str) -> dict[str, Any]:
project = "AURORA-" + hashlib.sha256(run_marker.encode()).hexdigest()[:10].upper()
document_text = (
f"{project} operating note. A knowledge change becomes canonical only after operator review and guarded "
"apply. Approval alone leaves canonical rows unchanged."
)
post_text = (
f"For {project}, reviewer approval is enough: a Leo proposal becomes canonical immediately, and no apply "
"step is needed."
)
return {
"project": project,
"document": {
"source_key": "operating_document",
"source_type": "article",
"title": f"{project} operating note",
"storage_path": f"/composition/{run_marker}/operating-note.txt",
"text": document_text,
"content_sha256": hashlib.sha256(document_text.encode()).hexdigest(),
},
"post": {
"source_key": "contradictory_post",
"source_type": "post",
"title": f"{project} contradictory post",
"url": f"https://x.example.test/{run_marker}",
"text": post_text,
"content_sha256": hashlib.sha256(post_text.encode()).hexdigest(),
},
}
def build_prompts(fixture: dict[str, Any], conversation_marker: str) -> dict[str, str]:
document = fixture["document"]
post = fixture["post"]
extraction_schema = {
"claim_candidates": [
{
"claim_key": "stable_key",
"text": "atomic claim",
"type": "structural|empirical|normative|meta|concept",
"confidence": 0.0,
"evidence": [{"source_key": "operating_document", "role": "grounds"}],
"edges": [{"edge_type": "contradicts", "target": "other_claim_key"}],
}
],
"source_candidates": [
{
"source_key": "operating_document|contradictory_post",
"source_type": "article|post",
"storage_path": "document path or null",
"url": "post URL or null",
"title": "source title",
"source_quality": "quality assessment",
"key_excerpt": "exact source substring",
"content_sha256": "supplied source SHA-256",
}
],
"dedupe_conflict_assessment": {
"database_search_query": "query actually used",
"potential_existing_claim_ids": [],
"conflicts": [
{
"from_claim_key": "claim key",
"to_claim_key": "claim key",
"relationship": "contradicts",
}
],
},
}
return {
"extract": (
f"Cory-style source intake for {fixture['project']}. Remember this conversation-only marker for the "
f"later reasoning turn: {conversation_marker}. First search the canonical KB for this project's topic so "
"you can report possible duplicates. Then extract atomic claims, exact evidence excerpts, provenance, "
"source quality, and explicit conflicts from the two new sources below. Do not stage, approve, apply, or "
"claim canonicality. Use source_key operating_document for the document and contradictory_post for the "
"post. Preserve the supplied SHA-256 values exactly. Every claim needs evidence; represent the sources' "
"conflict with a contradicts edge between claim keys. Return normal prose, then one final compact JSON "
f"line beginning {PACKET_PREFIX}. Schema: {json.dumps(extraction_schema, sort_keys=True)}\n\n"
f"DOCUMENT locator={document['storage_path']} sha256={document['content_sha256']}\n"
f"{document['text']}\n\nPOST locator={post['url']} sha256={post['content_sha256']}\n{post['text']}"
),
"reason": (
f"Cory asks about {fixture['project']}: 'approval means it is already in Leo, right?' Answer from the "
"canonical KB, explain the source conflict and which evidence is stronger, and distinguish approved from "
f"applied. Search without asking me for IDs. Then search proposals using {fixture['project']}, open the "
"matching proposal, inspect every relevant claim, run evidence for each claim with --format json so you can "
"report canonical source UUIDs rather than source keys, and run edges with --format json for at least one "
"claim. Recall the conversation-only marker from the earlier source-intake turn. End with one compact JSON "
f"line beginning {STATE_PREFIX}. Set phase exactly to 'final', proposal_id to the full discovered proposal "
"UUID, conversation_marker to the exact recalled marker, status exactly to 'applied', claim_ids and "
"source_ids to every full canonical UUID discovered from the DB, and conflict_edge to one real canonical "
"edge with from_claim, to_claim, edge_type."
),
}
def parse_prefixed_json(reply: str, prefix: str) -> dict[str, Any]:
for line in reversed(reply.splitlines()):
stripped = line.strip()
if not stripped.startswith(prefix):
continue
try:
value = json.loads(stripped[len(prefix) :].strip())
except json.JSONDecodeError as exc:
raise bound.CheckpointError(f"invalid {prefix} JSON: {exc}") from exc
if not isinstance(value, dict):
raise bound.CheckpointError(f"{prefix} payload must be a JSON object")
return value
raise bound.CheckpointError(f"reply did not contain a {prefix} line")
def validate_composition_packet(packet: dict[str, Any], fixture: dict[str, Any]) -> dict[str, Any]:
claims = packet.get("claim_candidates")
sources = packet.get("source_candidates")
assessment = packet.get("dedupe_conflict_assessment")
if not isinstance(claims, list) or len(claims) < 2:
raise bound.CheckpointError("composition packet must contain at least two claim candidates")
if not isinstance(sources, list) or len(sources) != 2:
raise bound.CheckpointError("composition packet must contain exactly the two supplied source candidates")
if not isinstance(assessment, dict) or not str(assessment.get("database_search_query") or "").strip():
raise bound.CheckpointError("composition packet must record the canonical dedupe search query")
source_by_key = {str(source.get("source_key")): source for source in sources if isinstance(source, dict)}
if set(source_by_key) != {"operating_document", "contradictory_post"}:
raise bound.CheckpointError("composition source keys do not match the supplied sources")
for label, fixture_key, locator_key in (
("operating_document", "document", "storage_path"),
("contradictory_post", "post", "url"),
):
source = source_by_key[label]
expected = fixture[fixture_key]
excerpt = str(source.get("key_excerpt") or "")
if not excerpt or excerpt not in expected["text"]:
raise bound.CheckpointError(f"{label} excerpt is not an exact substring of the supplied source")
if source.get("content_sha256") != expected["content_sha256"]:
raise bound.CheckpointError(f"{label} content SHA-256 does not match the supplied bytes")
if source.get(locator_key) != expected[locator_key]:
raise bound.CheckpointError(f"{label} locator does not match the supplied source")
claim_keys: set[str] = set()
evidence_source_keys: set[str] = set()
conflict_pairs: set[tuple[str, str]] = set()
for claim in claims:
if not isinstance(claim, dict):
raise bound.CheckpointError("every claim candidate must be an object")
claim_key = str(claim.get("claim_key") or "").strip()
claim_text = str(claim.get("text") or claim.get("headline") or "").strip()
if not claim_key or not claim_text or claim_key in claim_keys:
raise bound.CheckpointError("claim candidates need unique keys and nonempty atomic text")
claim_keys.add(claim_key)
evidence = claim.get("evidence")
if not isinstance(evidence, list) or not evidence:
raise bound.CheckpointError(f"claim {claim_key} has no evidence")
for item in evidence:
if isinstance(item, dict) and item.get("source_key"):
evidence_source_keys.add(str(item["source_key"]))
for edge in claim.get("edges") or []:
if isinstance(edge, dict) and edge.get("edge_type") == "contradicts" and edge.get("target"):
conflict_pairs.add((claim_key, str(edge["target"])))
if evidence_source_keys != set(source_by_key):
raise bound.CheckpointError("both supplied sources must ground at least one extracted claim")
if not any(left in claim_keys and right in claim_keys and left != right for left, right in conflict_pairs):
raise bound.CheckpointError("composition packet did not encode the source conflict as a claim edge")
conflicts = assessment.get("conflicts")
if not isinstance(conflicts, list) or not conflicts:
raise bound.CheckpointError("dedupe/conflict assessment omitted the observed contradiction")
return {
"claim_count": len(claims),
"source_count": len(sources),
"claim_keys": sorted(claim_keys),
"evidence_source_keys": sorted(evidence_source_keys),
"conflict_pairs": sorted([list(pair) for pair in conflict_pairs]),
}
def build_parent_packet(
packet: dict[str, Any], fixture: dict[str, Any], run_marker: str, agent_id: str
) -> dict[str, Any]:
return {
"id": _stable_uuid(run_marker, "rich-source-packet"),
"proposal_type": "attach_evidence",
"status": "pending_review",
"proposed_by_handle": "leo",
"proposed_by_agent_id": agent_id,
"channel": "clone_composition",
"source_ref": f"clone-composition:{run_marker}",
"rationale": f"Leo source composition packet for {fixture['project']}.",
"payload": packet,
}
def resolve_leo_agent_id(container: str, database: str) -> str:
result = bound._psql_json(
container,
database,
"""\\set ON_ERROR_STOP on
begin transaction read only;
select jsonb_build_object(
'agent_id', (
select id::text from public.agents
where lower(handle) in ('leo', 'leoclean')
order by case lower(handle) when 'leo' then 0 else 1 end, id
limit 1
)
)::text;
rollback;
""",
)
try:
return str(uuid.UUID(str(result.get("agent_id"))))
except ValueError as exc:
raise bound.CheckpointError("clone has no canonical leo/leoclean agent row for attribution") from exc
def _replace_generic_receipt(skill_text: str) -> str:
return skill_text.replace(
"""End the final answer with one machine-readable line using the full proposal
UUID and the row state you observed:
`KB_STATE: {"proposal_id":"<uuid>","status":"pending_review|approved|applied","applied":false}`
""",
"",
)
def patch_composition_bridge(
temp_profile: Path, *, container: str, database: str, fixture: dict[str, Any]
) -> dict[str, Any]:
bridge = bound.patch_temp_bridge(temp_profile, container, database)
skill_path = Path(bridge["bridge_skill_path"])
skill_text = _replace_generic_receipt(skill_path.read_text(encoding="utf-8"))
binding = f"""
## Disposable Source Composition Checkpoint
This no-send profile is testing source composition for `{fixture["project"]}`
against one disposable clone. You may only search and read the clone. You cannot
stage, review, approve, apply, send, or access production. The prompt defines
either a `COMPOSITION_PACKET:` extraction receipt or a `COMPOSITION_STATE:`
canonical reasoning receipt; emit only the receipt requested by that turn.
"""
skill_text = bound.inject_skill_binding(skill_text, binding.lstrip())
bound._detach_and_write(skill_path, skill_text, mode=0o600)
bridge["bridge_skill_sha256"] = bound.sha256_bytes(skill_text.encode())
bridge["composition_project"] = fixture["project"]
return bridge
def _exclude_rows(rows: list[dict[str, Any]], columns: tuple[str, ...]) -> str:
if not rows:
return "true"
matches = []
for row in rows:
matches.append(
"(" + " and ".join(f"t.{column}::text = {ap.sql_literal(str(row[column]))}" for column in columns) + ")"
)
return "not (" + " or ".join(matches) + ")"
def unrelated_guard_snapshot(container: str, database: str, child: dict[str, Any]) -> dict[str, Any]:
rows = guarded._expected_bundle_rows(child["payload"]["apply_payload"])
predicates = {
"public.claims": _exclude_rows(rows["claims"], ("id",)),
"public.sources": _exclude_rows(rows["sources"], ("id",)),
"public.claim_evidence": _exclude_rows(rows["claim_evidence"], ("claim_id", "source_id", "role")),
"public.claim_edges": _exclude_rows(rows["claim_edges"], ("from_claim", "to_claim", "edge_type")),
"public.reasoning_tools": _exclude_rows(rows["reasoning_tools"], ("id",)),
"kb_stage.kb_proposals": f"t.id <> {ap.sql_literal(child['id'])}::uuid",
lifecycle.APPROVAL_TABLE: f"t.proposal_id <> {ap.sql_literal(child['id'])}::uuid",
}
pairs = [
f"""'{table}', jsonb_build_object(
'count', (select count(*) from {table} t where {predicates[table]}),
'rowset_md5', (select md5(coalesce(string_agg(to_jsonb(t)::text, E'\\n'
order by to_jsonb(t)::text), '')) from {table} t where {predicates[table]})
)"""
for table in TABLES
]
return bound._psql_json(
container,
database,
"""\\set ON_ERROR_STOP on
begin transaction read only;
select jsonb_build_object(
"""
+ ",\n ".join(pairs)
+ """
)::text;
rollback;
""",
)
def _turn_args(args: argparse.Namespace, phase: str, prompt: str) -> argparse.Namespace:
return SimpleNamespace(
chat_id=args.chat_id,
user_id=args.user_id,
user_name=args.user_name,
prompt=prompt,
prompt_id=phase,
run_id=args.run_marker,
turn_timeout=args.turn_timeout,
)
async def run_turn(
args: argparse.Namespace,
temp_profile: Path,
*,
phase: str,
prompt: str,
provider_environment: dict[str, str],
tool_log: Path,
) -> dict[str, Any]:
proof_args = {
"run_nonce": args.tool_run_nonce,
"database_identity": args.target_database_identity,
"require_database_read_only": False,
}
before = bound.read_tool_proof(tool_log, args.bound_container_id, args.db, **proof_args)
gateway = await bound.invoke_gateway_subprocess(
_turn_args(args, phase, prompt), temp_profile, provider_environment=provider_environment
)
after = bound.read_tool_proof(tool_log, args.bound_container_id, args.db, **proof_args)
return {
"phase": phase,
"prompt_sha256": hashlib.sha256(prompt.encode()).hexdigest(),
"prompt": prompt,
"gateway": gateway,
"tool_invocations": after["invocations"][before["invocation_count"] :],
}
def _argvs(turn: dict[str, Any]) -> list[list[str]]:
return [
[str(value) for value in invocation.get("argv", [])]
for invocation in turn.get("tool_invocations", [])
if invocation.get("argv")
]
def _searched_project(turn: dict[str, Any], project: str) -> bool:
return any(
len(argv) >= 2 and argv[0] in {"search", "context"} and project.lower() in argv[1].lower()
for argv in _argvs(turn)
)
def _searched_recorded_dedupe_query(turn: dict[str, Any], packet: dict[str, Any]) -> bool:
assessment = packet.get("dedupe_conflict_assessment") or {}
query = str(assessment.get("database_search_query") or "")
return bool(query) and any(
len(argv) >= 2 and argv[0] in {"search", "context"} and argv[1] == query
for argv in _argvs(turn)
)
def _searched_semantically_without_ids(turn: dict[str, Any], row_ids: list[str]) -> bool:
terms = {"approval", "approved", "apply", "applied", "canonical", "review"}
return any(
len(argv) >= 2
and argv[0] in {"search", "context"}
and not any(row_id in argv[1] for row_id in row_ids)
and len(terms & set(argv[1].lower().split())) >= 2
for argv in _argvs(turn)
)
def _searched_composed_proposal(turn: dict[str, Any], project: str) -> bool:
return any(
len(argv) >= 2 and argv[0] == "search-proposals" and project.lower() in argv[1].lower()
for argv in _argvs(turn)
)
def _read_claim(turn: dict[str, Any], claim_id: str) -> bool:
return any(argv[:2] == ["show", claim_id] for argv in _argvs(turn))
def _read_claim_edges(turn: dict[str, Any], claim_id: str) -> bool:
return any(argv[:2] == ["edges", claim_id] for argv in _argvs(turn))
def _read_claim_evidence(turn: dict[str, Any], claim_id: str) -> bool:
return any(
argv[:2] == ["evidence", claim_id]
and argv[2:] in (["--format", "json"], ["--format=json"])
for argv in _argvs(turn)
)
def _read_claim_material(turn: dict[str, Any], claim_id: str) -> bool:
return _read_claim(turn, claim_id) or _read_claim_evidence(turn, claim_id)
def _read_exact_proposal(turn: dict[str, Any], proposal_id: str) -> bool:
return any(argv[:2] == ["show-proposal", proposal_id] for argv in _argvs(turn))
def merge_transcript_events(gateways: list[dict[str, Any]]) -> list[dict[str, Any]]:
"""Collapse cumulative session traces without hiding events that lack an ID."""
merged: dict[tuple[str, str], dict[str, Any]] = {}
order: list[tuple[str, str]] = []
for gateway_index, gateway in enumerate(gateways):
events = (gateway.get("transcript_tool_trace") or {}).get("events", [])
for event_index, event in enumerate(events):
phase = str(event.get("phase") or "")
call_id = str(event.get("tool_call_id") or "")
if not call_id:
call_id = f"missing:{gateway_index}:{event_index}"
key = (phase, call_id)
if key not in merged:
order.append(key)
merged[key] = event
return [merged[key] for key in order]
def terminal_trace_consistency(events: list[dict[str, Any]], tool_proof: dict[str, Any]) -> dict[str, Any]:
"""Reconcile bounded transcript receipts with nonce-bound wrapper receipts."""
terminal_calls = {
str(event.get("tool_call_id")): event
for event in events
if event.get("phase") == "call" and event.get("tool_name") == "terminal"
}
results = {
str(event.get("tool_call_id")): event
for event in events
if event.get("phase") == "result" and event.get("tool_call_id")
}
summary = bound.transcript_terminal_attempt_summary(events)
known_exit_codes = summary.get("known_exit_codes") or {}
unknown_ids = sorted(set(terminal_calls) - set(known_exit_codes))
unknown_receipted_and_truncated = sorted(
call_id
for call_id in unknown_ids
if call_id in results and results[call_id].get("content_truncated") is True
)
every_call_has_result = set(terminal_calls) <= set(results)
unknown_results_are_valid = unknown_ids == unknown_receipted_and_truncated
count_matches = len(terminal_calls) == int(tool_proof.get("invocation_count") or 0)
passes = (
bool(terminal_calls)
and every_call_has_result
and unknown_results_are_valid
and summary.get("rejected_call_count") == 0
and summary.get("nonzero_call_count") == 0
and count_matches
and tool_proof.get("all_bound_to_supplied_target") is True
and tool_proof.get("all_completed_successfully") is True
)
return {
**summary,
"terminal_call_ids": sorted(terminal_calls),
"result_call_ids": sorted(results),
"unknown_result_call_ids": unknown_ids,
"unknown_receipted_and_truncated_call_ids": unknown_receipted_and_truncated,
"every_terminal_call_has_result": every_call_has_result,
"unknown_results_are_receipted_and_truncated": unknown_results_are_valid,
"nonce_bound_invocation_count": int(tool_proof.get("invocation_count") or 0),
"nonce_bound_invocation_count_matches": count_matches,
"passes": passes,
}
def _state_matches(state: dict[str, Any], *, conversation_marker: str, child: dict[str, Any]) -> bool:
payload = child["payload"]["apply_payload"]
expected_claim_ids = sorted(row["id"] for row in payload["claims"])
expected_source_ids = sorted(row["id"] for row in payload["sources"])
edges = payload["edges"]
edge = state.get("conflict_edge") if isinstance(state.get("conflict_edge"), dict) else {}
return (
state.get("phase") == "final"
and (state.get("conversation_marker") or state.get("marker")) == conversation_marker
and state.get("proposal_id") == child["id"]
and state.get("status") == "applied"
and sorted(state.get("claim_ids") or []) == expected_claim_ids
and sorted(state.get("source_ids") or []) == expected_source_ids
and bool(edges)
and any(
edge.get("from_claim") == expected["from_claim"]
and edge.get("to_claim") == expected["to_claim"]
and edge.get("edge_type") == expected["edge_type"]
for expected in edges
)
)
def _service_unchanged(before: dict[str, Any] | None, after: dict[str, Any] | None) -> bool:
return bool(before and after and before.get("returncode") == 0 and before == after)
def expected_table_deltas(child: dict[str, Any]) -> dict[str, int]:
rows = guarded._expected_bundle_rows(child["payload"]["apply_payload"])
return {
"public.claims": len(rows["claims"]),
"public.sources": len(rows["sources"]),
"public.claim_evidence": len(rows["claim_evidence"]),
"public.claim_edges": len(rows["claim_edges"]),
"public.reasoning_tools": len(rows["reasoning_tools"]),
"kb_stage.kb_proposals": 1,
lifecycle.APPROVAL_TABLE: 1,
}
def base_snapshot_matches(target: dict[str, Any], production: dict[str, Any]) -> bool:
return all(
target.get(section, {}).get(table) == production.get(section, {}).get(table)
for section in ("counts", "rowset_md5")
for table in PRODUCTION_TABLES
)
def gate_schema_manifest(container: str, database: str) -> dict[str, Any]:
return bound._psql_json(
container,
database,
"""\\set ON_ERROR_STOP on
begin transaction read only;
select jsonb_build_object(
'approval_table', to_regclass('kb_stage.kb_proposal_approvals')::text,
'review_principals_table', to_regclass('kb_stage.kb_review_principals')::text,
'review_role_exists', exists(select 1 from pg_roles where rolname = 'kb_review'),
'apply_role_exists', exists(select 1 from pg_roles where rolname = 'kb_apply'),
'approve_function', to_regprocedure(
'kb_stage.approve_strict_proposal(uuid,text,jsonb,text,text)'
)::text,
'assert_function', to_regprocedure(
'kb_stage.assert_approved_proposal(uuid,text,jsonb,text,uuid,timestamptz,text)'
)::text,
'finish_function', to_regprocedure(
'kb_stage.finish_approved_proposal(uuid,text,jsonb,text,uuid,timestamptz,text,text)'
)::text
)::text;
rollback;
""",
)
def clone_gate_schema_ready(manifest: dict[str, Any]) -> bool:
return (
manifest.get("approval_table") == lifecycle.APPROVAL_TABLE
and manifest.get("review_principals_table") == "kb_stage.kb_review_principals"
and manifest.get("review_role_exists") is True
and manifest.get("apply_role_exists") is True
and bool(manifest.get("approve_function"))
and bool(manifest.get("assert_function"))
and bool(manifest.get("finish_function"))
)
def source_manifest() -> list[dict[str, Any]]:
paths = (
Path(__file__).resolve(),
(HERE / "bootstrap_clone_kb_gate.py").resolve(),
(HERE / "kb_apply_prereqs.sql").resolve(),
(HERE / "run_leo_clone_bound_handler_checkpoint.py").resolve(),
(HERE / "run_leo_clone_lifecycle_checkpoint.py").resolve(),
(HERE / "stage_normalized_proposal.py").resolve(),
(HERE / "kb_proposal_normalize.py").resolve(),
(HERE / "kb_proposal_review_packet.py").resolve(),
(HERE / "kb_rich_proposal_creation_plan.py").resolve(),
(HERE / "apply_worker.py").resolve(),
(HERE / "run_approve_claim_clone_canary.py").resolve(),
(HERE / "approve_proposal.py").resolve(),
(HERE / "apply_proposal.py").resolve(),
)
return [
{
"repo_relative_path": path.relative_to(REPO_ROOT.resolve()).as_posix(),
"sha256": hashlib.sha256(path.read_bytes()).hexdigest(),
"size_bytes": path.stat().st_size,
}
for path in paths
]
def validate_args(args: argparse.Namespace) -> None:
lifecycle._validate_marker(args.run_marker, "--run-marker")
lifecycle._validate_marker(args.conversation_marker, "--conversation-marker")
if args.run_marker == args.conversation_marker:
raise bound.CheckpointError("run and conversation markers must be distinct")
if args.container == bound.PRODUCTION_CONTAINER:
raise bound.CheckpointError("--container must be a disposable non-production container")
if not bound.SAFE_DOCKER_NAME_RE.fullmatch(args.container):
raise bound.CheckpointError("--container must be an explicit Docker name")
if not bound.SAFE_DB_NAME_RE.fullmatch(args.db):
raise bound.CheckpointError("--db must be an explicit database name")
if not args.copy_model_auth or not args.operator_review or not args.guarded_apply:
raise bound.CheckpointError("--copy-model-auth, --operator-review, and --guarded-apply are required")
if args.turn_timeout <= 0:
raise bound.CheckpointError("--turn-timeout must be positive")
args.output = bound.validate_private_output_path(args.output)
async def run_checkpoint(args: argparse.Namespace) -> dict[str, Any]:
validate_args(args)
fixture = build_source_fixture(args.run_marker)
prompts = build_prompts(fixture, args.conversation_marker)
report: dict[str, Any] = {
"schema": SCHEMA,
"generated_at_utc": bound.utc_now(),
"current_canary": "source bytes -> Leo extraction -> strict staged child -> review/apply -> restarted reasoning",
"required_tier": "live_vps_no_send_disposable_full_data_clone",
"posted_to_telegram": False,
"production_writes_attempted": False,
"production_service_restart_attempted": False,
"fixture": {
"project": fixture["project"],
"document_sha256": fixture["document"]["content_sha256"],
"post_sha256": fixture["post"]["content_sha256"],
},
"errors": [],
"turns": {},
"source_manifest_before": source_manifest(),
"output": str(args.output),
}
temp_profile: Path | None = None
tool_log: Path | None = None
bridge: dict[str, Any] = {}
provider_environment: dict[str, str] = {}
provider_secret_values: tuple[str, ...] = ()
target_container_id: str | None = None
target_identity_before: dict[str, Any] | None = None
target_guard_before: dict[str, Any] | None = None
target_unrelated_before: dict[str, Any] | None = None
production_guard_before: dict[str, Any] | None = None
production_gate_schema_before: dict[str, Any] | None = None
production_service_before: dict[str, Any] | None = None
live_bridge_before: dict[str, str | None] | None = None
packet: dict[str, Any] | None = None
child: dict[str, Any] | None = None
try:
target_identity_before, production_identity = lifecycle.assert_disposable_target(args.container, args.db)
target_container_id = str(target_identity_before["id"])
args.bound_container_id = target_container_id
report["target"] = {
"requested_container": args.container,
"bound_container_id": target_container_id,
"container_identity_before": target_identity_before,
"isolation_checks": bound.validate_disposable_target_identity(target_identity_before, production_identity),
}
production_guard_before = bound.database_guard_snapshot(
bound.PRODUCTION_CONTAINER, bound.PRODUCTION_DB, tables=PRODUCTION_TABLES
)
target_base_guard = bound.database_guard_snapshot(target_container_id, args.db, tables=PRODUCTION_TABLES)
if not base_snapshot_matches(target_base_guard, production_guard_before):
raise bound.CheckpointError(
"target base rows are not an exact production clone before clone-only gate additions"
)
target_guard_before = bound.database_guard_snapshot(target_container_id, args.db, tables=TABLES)
target_gate_schema = gate_schema_manifest(target_container_id, args.db)
if not clone_gate_schema_ready(target_gate_schema):
raise bound.CheckpointError(
"clone-only guarded review/apply prerequisites are incomplete: "
+ json.dumps(target_gate_schema, sort_keys=True)
)
production_gate_schema_before = gate_schema_manifest(bound.PRODUCTION_CONTAINER, bound.PRODUCTION_DB)
if (
target_guard_before["database_identity"]["system_identifier"]
== production_guard_before["database_identity"]["system_identifier"]
):
raise bound.CheckpointError("target and production share a PostgreSQL system identifier")
args.target_database_identity = target_guard_before["database_identity"]
production_service_before = bound.service_state()
live_bridge_before = bound.bridge_hashes()
report["production_invariants"] = {
"container_identity": production_identity,
"guard_snapshot_before": production_guard_before,
"gate_schema_before": production_gate_schema_before,
"service_before": production_service_before,
"live_bridge_hashes_before": live_bridge_before,
}
report["target_base_guard_snapshot"] = target_base_guard
report["target_gate_schema"] = target_gate_schema
report["target_guard_snapshot_before"] = target_guard_before
missing_secrets = [
label
for label, path in (
("review", Path(args.review_secrets_file)),
("apply", Path(args.apply_secrets_file)),
)
if not path.is_file()
]
if missing_secrets:
raise bound.CheckpointError(
"required separated clone credential file(s) are absent: " + ", ".join(missing_secrets)
)
temp_profile, copy_audit = bound.copy_profile(run_id=args.run_marker, prompt_id="composition")
report["temporary_profile_copy_audit"] = copy_audit
report["model_auth_binding"] = bound.copy_ephemeral_model_auth(temp_profile)
provider_environment, environment_audit = bound.load_ephemeral_provider_environment(temp_profile)
provider_secret_values = tuple(provider_environment.values())
report["model_auth_binding"]["environment_binding"] = environment_audit
bridge = patch_composition_bridge(
temp_profile, container=target_container_id, database=args.db, fixture=fixture
)
report["temporary_bridge"] = bridge
tool_log = Path(bridge["tool_log_path"])
args.tool_run_nonce = bridge["run_nonce"]
extract_turn = await run_turn(
args,
temp_profile,
phase="T1_extract_sources",
prompt=prompts["extract"],
provider_environment=provider_environment,
tool_log=tool_log,
)
lifecycle._require_gateway_turn(extract_turn)
report["turns"]["T1_extract_sources"] = extract_turn
packet = parse_prefixed_json(str(extract_turn["gateway"].get("reply") or ""), PACKET_PREFIX)
report["packet_validation"] = validate_composition_packet(packet, fixture)
guard_after_extraction = bound.database_guard_snapshot(target_container_id, args.db, tables=TABLES)
report["target_guard_snapshot_after_extraction"] = guard_after_extraction
if guard_after_extraction != target_guard_before:
raise bound.CheckpointError("source extraction changed the clone before staging")
agent_id = resolve_leo_agent_id(target_container_id, args.db)
parent = build_parent_packet(packet, fixture, args.run_marker, agent_id)
stage_result = normalized_stage.stage_normalized_child(args.container, args.db, parent)
if stage_result["bound_container_id"] != target_container_id:
raise bound.CheckpointError("normalized staging rebound to a different container identity")
child = stage_result["child"]
report["normalized_child"] = {
"id": child["id"],
"proposal_type": child["proposal_type"],
"status": child["status"],
"source_ref": child["source_ref"],
"parent_packet_sha256": child["parent_packet_sha256"],
"payload_sha256": child["payload_sha256"],
"planned_row_ids": {
"claims": [row["id"] for row in child["payload"]["apply_payload"]["claims"]],
"sources": [row["id"] for row in child["payload"]["apply_payload"]["sources"]],
},
}
report["stage_receipt"] = stage_result["database_receipt"]
expected_rows = guarded._expected_bundle_rows(child["payload"]["apply_payload"])
empty_rows = {key: [] for key in expected_rows}
if (
guarded._exact_bundle_readback(target_container_id, args.db, child["payload"]["apply_payload"])
!= empty_rows
):
raise bound.CheckpointError("canonical rows appeared before review/apply")
pending = guarded._proposal_readback(target_container_id, args.db, child["id"])
report["pending_readback"] = pending
if not pending or not bound._state_semantics(pending, "pending_review")["all"]:
raise bound.CheckpointError("normalized child was not exactly pending and unapplied")
target_unrelated_before = unrelated_guard_snapshot(target_container_id, args.db, child)
review_dry, review_apply = lifecycle.run_operator_review(args, child["id"])
approved = guarded._proposal_readback(target_container_id, args.db, child["id"])
approval_snapshot = guarded._approval_snapshot_readback(target_container_id, args.db, child["id"])
report["operator_review"] = {
"dry_run": lifecycle._command_receipt(review_dry),
"apply": lifecycle._command_receipt(review_apply),
"approved_readback": approved,
"approval_snapshot": approval_snapshot,
}
apply_dry, apply_execute = lifecycle.run_guarded_apply(args, child["id"])
applied = guarded._proposal_readback(target_container_id, args.db, child["id"])
approval_after = guarded._approval_snapshot_readback(target_container_id, args.db, child["id"])
final_rows = guarded._exact_bundle_readback(target_container_id, args.db, child["payload"]["apply_payload"])
report["guarded_apply"] = {
"dry_run": lifecycle._command_receipt(apply_dry),
"apply": lifecycle._command_receipt(apply_execute),
"applied_readback": applied,
"approval_snapshot_after_apply": approval_after,
}
report["final_canonical_rows"] = final_rows
if not guarded._approval_transition_valid(pending, approved):
raise bound.CheckpointError("operator review did not produce the exact approved transition")
if not guarded._apply_transition_valid(approved, applied):
raise bound.CheckpointError("guarded apply transition is invalid")
if approval_snapshot != approval_after:
raise bound.CheckpointError("apply changed the immutable approval snapshot")
if final_rows != expected_rows:
raise bound.CheckpointError("canonical source-derived rows differ from the reviewed payload")
reason_turn = await run_turn(
args,
temp_profile,
phase="T5_reason_after_restart",
prompt=prompts["reason"],
provider_environment=provider_environment,
tool_log=tool_log,
)
lifecycle._require_gateway_turn(reason_turn)
report["turns"]["T5_reason_after_restart"] = reason_turn
state = parse_prefixed_json(str(reason_turn["gateway"].get("reply") or ""), STATE_PREFIX)
report["final_state_receipt"] = state
report["final_state_matches_rows"] = _state_matches(
state, conversation_marker=args.conversation_marker, child=child
)
t1_child = extract_turn["gateway"].get("child_process") or {}
t5_child = reason_turn["gateway"].get("child_process") or {}
report["isolated_restart"] = {
"prior_child_absent": t1_child.get("alive_after_readback") is False
and t1_child.get("process_group_alive_after_readback") is False,
"child_pid_changed": t1_child.get("pid") != t5_child.get("pid"),
"same_session_key": bool(extract_turn["gateway"].get("session_key"))
and extract_turn["gateway"].get("session_key") == reason_turn["gateway"].get("session_key"),
"same_persisted_session_id": (
bool((extract_turn["gateway"].get("transcript_tool_trace") or {}).get("session_id"))
and (extract_turn["gateway"].get("transcript_tool_trace") or {}).get("session_id")
== (reason_turn["gateway"].get("transcript_tool_trace") or {}).get("session_id")
),
}
except Exception as exc:
report["errors"].append({"type": type(exc).__name__, "message": str(exc)})
report["traceback_tail"] = traceback.format_exc().splitlines()[-16:]
finally:
provider_environment.clear()
child_cleanup = bound.cleanup_active_gateway_children()
try:
if not tool_log or not bridge or not target_container_id or not target_guard_before:
raise bound.CheckpointError("tool proof prerequisites were not established")
tool_proof = bound.read_tool_proof(
tool_log,
target_container_id,
args.db,
run_nonce=bridge["run_nonce"],
database_identity=target_guard_before["database_identity"],
require_database_read_only=False,
)
except Exception as exc:
report["errors"].append({"type": type(exc).__name__, "message": f"tool proof: {exc}"})
tool_proof = {
"invocations": [],
"invocation_count": 0,
"all_bound_to_supplied_target": False,
"all_completed_successfully": False,
}
report["tool_proof"] = tool_proof
temp_root = temp_profile.parent if temp_profile else None
cleanup_clear = not bound._ACTIVE_GATEWAY_CHILDREN and all(
not item.get("alive_after_cleanup") and not item.get("process_group_alive_after_cleanup")
for item in child_cleanup.values()
)
temp_removed = bound.remove_tree(temp_root) if cleanup_clear else False
report["cleanup"] = {
"active_gateway_child_cleanup": child_cleanup,
"active_gateway_registry_clear": not bound._ACTIVE_GATEWAY_CHILDREN,
"temp_profile_removed": temp_removed,
"absence_verified_independently": bound.temp_path_absent(temp_root),
"active_temp_root_registry_clear": (temp_root not in bound._ACTIVE_TEMP_ROOTS if temp_root else True),
}
target_guard_after = None
target_identity_after = None
target_unrelated_after = None
if target_container_id:
try:
target_identity_after = bound.container_identity(args.container)
if target_identity_after.get("id") != target_container_id:
raise bound.CheckpointError("target name no longer resolves to the pinned identity")
report.setdefault("target", {})["container_identity_after"] = target_identity_after
target_guard_after = bound.database_guard_snapshot(target_container_id, args.db, tables=TABLES)
report["target_guard_snapshot_after"] = target_guard_after
if child and target_unrelated_before is not None:
target_unrelated_after = unrelated_guard_snapshot(target_container_id, args.db, child)
except Exception as exc:
report["errors"].append({"type": type(exc).__name__, "message": f"target postflight: {exc}"})
production_guard_after = None
production_gate_schema_after = None
try:
production_guard_after = bound.database_guard_snapshot(
bound.PRODUCTION_CONTAINER, bound.PRODUCTION_DB, tables=PRODUCTION_TABLES
)
production_gate_schema_after = gate_schema_manifest(bound.PRODUCTION_CONTAINER, bound.PRODUCTION_DB)
except Exception as exc:
report["errors"].append({"type": type(exc).__name__, "message": f"production postflight: {exc}"})
production_service_after = bound.service_state()
live_bridge_after = bound.bridge_hashes()
production = report.setdefault("production_invariants", {})
production.update(
{
"guard_snapshot_after": production_guard_after,
"guard_snapshot_unchanged": production_guard_before is not None
and production_guard_before == production_guard_after,
"gate_schema_after": production_gate_schema_after,
"gate_schema_unchanged": production_gate_schema_before is not None
and production_gate_schema_before == production_gate_schema_after,
"service_after": production_service_after,
"service_unchanged": _service_unchanged(production_service_before, production_service_after),
"live_bridge_hashes_after": live_bridge_after,
"live_bridge_unchanged": live_bridge_before is not None and live_bridge_before == live_bridge_after,
}
)
turns = report.get("turns") or {}
extraction = turns.get("T1_extract_sources") or {}
reasoning = turns.get("T5_reason_after_restart") or {}
gateways = [turn.get("gateway") or {} for turn in (extraction, reasoning)]
merged_events = merge_transcript_events(gateways)
terminal_consistency = terminal_trace_consistency(merged_events, tool_proof)
report["merged_transcript_event_count"] = len(merged_events)
report["terminal_trace_consistency"] = terminal_consistency
expected_claim_ids = [row["id"] for row in child["payload"]["apply_payload"]["claims"]] if child else []
expected_source_ids = [row["id"] for row in child["payload"]["apply_payload"]["sources"]] if child else []
generated_row_ids = [
*expected_claim_ids,
*expected_source_ids,
*([child["id"]] if child else []),
]
reply = str((reasoning.get("gateway") or {}).get("reply") or "").lower()
transcript_calls = [
event.get("tool_name")
for event in merged_events
if event.get("phase") == "call"
]
source_manifest_after = source_manifest()
report["source_manifest_after"] = source_manifest_after
checks = {
"clone_base_rows_match_production_before_gate_use": base_snapshot_matches(
report.get("target_base_guard_snapshot") or {},
production.get("guard_snapshot_before") or {},
),
"clone_only_gate_schema_ready": clone_gate_schema_ready(report.get("target_gate_schema") or {}),
"source_packet_validated": bool(report.get("packet_validation")),
"extraction_searched_existing_kb": _searched_recorded_dedupe_query(extraction, packet or {}),
"extraction_changed_no_database_rows": report.get("target_guard_snapshot_after_extraction")
== report.get("target_guard_snapshot_before"),
"normalized_child_staged": child is not None
and report.get("stage_receipt", {}).get("status") == "pending_review",
"source_hashes_preserved": bool(child)
and {fixture["document"]["content_sha256"], fixture["post"]["content_sha256"]}
<= {row["hash"] for row in child["payload"]["apply_payload"]["sources"]},
"canonical_rows_match_reviewed_payload": bool(child)
and report.get("final_canonical_rows") == guarded._expected_bundle_rows(child["payload"]["apply_payload"]),
"immutable_approval_survived_apply": report.get("operator_review", {}).get("approval_snapshot")
== report.get("guarded_apply", {}).get("approval_snapshot_after_apply"),
"target_table_deltas_exact": bool(child and target_guard_before and target_guard_after)
and lifecycle._table_deltas(target_guard_before["counts"], target_guard_after["counts"])
== expected_table_deltas(child),
"target_database_identity_stable": bool(target_guard_before and target_guard_after)
and target_guard_before.get("database_identity") == target_guard_after.get("database_identity"),
"reasoning_searched_without_ids": _searched_semantically_without_ids(reasoning, generated_row_ids),
"reasoning_searched_composed_proposal": _searched_composed_proposal(reasoning, fixture["project"]),
"reasoning_read_exact_proposal": bool(child) and _read_exact_proposal(reasoning, child["id"]),
"reasoning_read_every_composed_claim": bool(expected_claim_ids)
and all(_read_claim_material(reasoning, claim_id) for claim_id in expected_claim_ids),
"reasoning_read_every_claim_evidence": bool(expected_claim_ids)
and all(_read_claim_evidence(reasoning, claim_id) for claim_id in expected_claim_ids),
"reasoning_read_conflict_edges": bool(expected_claim_ids)
and any(_read_claim_edges(reasoning, claim_id) for claim_id in expected_claim_ids),
"reasoning_answered_cory_state_and_conflict": ("approved" in reply or "approval" in reply)
and "applied" in reply
and "canonical" in reply
and "conflict" in reply,
"final_state_receipt_matches_rows": report.get("final_state_matches_rows") is True,
"isolated_restart_and_memory_survived": bool(report.get("isolated_restart"))
and all(report.get("isolated_restart", {}).values()),
"all_tool_calls_bound_and_successful": tool_proof.get("all_bound_to_supplied_target") is True
and tool_proof.get("all_completed_successfully") is True,
"terminal_results_complete_and_first_try": terminal_consistency.get("passes") is True,
"all_gateway_children_clean": bool(gateways)
and all(
(gateway.get("child_process") or {}).get("readiness_verified") is True
and (gateway.get("child_process") or {}).get("timed_out") is False
and (gateway.get("child_process") or {}).get("exitcode") == 0
and (gateway.get("child_process") or {}).get("result_transport") == "private_temp_file"
and ((gateway.get("child_process") or {}).get("termination") or {}).get("attempted") is False
and (gateway.get("child_process") or {}).get("alive_after_readback") is False
and (gateway.get("child_process") or {}).get("process_group_alive_after_readback") is False
for gateway in gateways
),
"gateway_tool_surfaces_are_read_only_and_no_send": bool(gateways)
and all(
set((gateway.get("tool_surface") or {}).get("actual_registry_tools") or [])
== {"skills_list", "skill_view", "terminal"}
and set((gateway.get("tool_surface") or {}).get("allowed_tools") or [])
== {"skills_list", "skill_view", "terminal"}
and (gateway.get("tool_surface") or {}).get("gateway_adapters_verified_mapping") is True
and (gateway.get("tool_surface") or {}).get("gateway_adapter_count") == 0
and (gateway.get("tool_surface") or {}).get("send_message_tool_enabled") is False
and (gateway.get("tool_surface") or {}).get("terminal_restricted_to_clone_wrapper") is True
and (gateway.get("tool_surface") or {}).get("terminal_subprocess_inherits_provider_credentials")
is False
and gateway.get("model_free_fallback_used") is False
for gateway in gateways
),
"all_transcript_tool_calls_allowlisted": bool(transcript_calls)
and all(name in {"skills_list", "skill_view", "terminal"} for name in transcript_calls),
"target_name_still_pinned": bool(target_identity_before and target_identity_after)
and target_identity_before == target_identity_after,
"unrelated_clone_rows_unchanged": target_unrelated_before is not None
and target_unrelated_before == target_unrelated_after,
"production_database_unchanged": production.get("guard_snapshot_unchanged") is True,
"production_gate_schema_unchanged": production.get("gate_schema_unchanged") is True,
"production_service_unchanged": production.get("service_unchanged") is True,
"live_bridge_unchanged": production.get("live_bridge_unchanged") is True,
"checkpoint_source_files_unchanged": report.get("source_manifest_before") == source_manifest_after,
"no_telegram_send": report.get("posted_to_telegram") is False
and all(gateway.get("posted_to_telegram") is False for gateway in gateways),
"temporary_profile_removed": report.get("cleanup", {}).get("temp_profile_removed") is True
and report.get("cleanup", {}).get("absence_verified_independently") is True
and report.get("cleanup", {}).get("active_gateway_registry_clear") is True
and report.get("cleanup", {}).get("active_temp_root_registry_clear") is True,
}
report["checks"] = checks
report["status"] = "pass" if not report["errors"] and all(checks.values()) else "fail"
report["claim_ceiling"] = (
"A pass proves no-send source extraction, deterministic hash-bound normalization, clone-only guarded "
"canonical apply, and restarted open-ended reasoning over the composed rows. It does not prove Telegram "
"delivery, production mutation, scheduled identity recomposition, or semantic behavior beyond this case."
)
report["completed_at_utc"] = bound.utc_now()
report = bound.redact_value(report, secret_values=provider_secret_values)
bound.write_report(args.output, report, secret_values=provider_secret_values)
return report
def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--container", required=True)
parser.add_argument("--db", required=True)
parser.add_argument("--output", required=True, type=Path)
parser.add_argument("--run-marker", default=None)
parser.add_argument("--conversation-marker", default=None)
parser.add_argument("--chat-id", default=bound.DEFAULT_CHAT_ID)
parser.add_argument("--user-id", default=bound.DEFAULT_USER_ID)
parser.add_argument("--user-name", default="codex clone composition checkpoint")
parser.add_argument("--turn-timeout", type=int, default=300)
parser.add_argument("--review-secrets-file", default=lifecycle.DEFAULT_REVIEW_SECRETS_FILE)
parser.add_argument("--apply-secrets-file", default=lifecycle.DEFAULT_APPLY_SECRETS_FILE)
parser.add_argument("--copy-model-auth", action="store_true")
parser.add_argument("--operator-review", action="store_true")
parser.add_argument("--guarded-apply", action="store_true")
args = parser.parse_args(argv)
args.run_marker = args.run_marker or lifecycle.new_marker("leo-composition")
args.conversation_marker = args.conversation_marker or lifecycle.new_marker("composition-memory")
return args
def main(argv: list[str] | None = None) -> int:
args = parse_args(argv)
try:
with bound.termination_cleanup_handlers():
report = asyncio.run(run_checkpoint(args))
except bound.CheckpointError as exc:
print(json.dumps({"status": "rejected", "error": str(exc)}, sort_keys=True))
return 2
print(
json.dumps(
{
"status": report.get("status"),
"output": str(args.output),
"checks_passed": sum(bool(value) for value in report.get("checks", {}).values()),
"checks_total": len(report.get("checks", {})),
"error_count": len(report.get("errors", [])),
},
sort_keys=True,
)
)
return 0 if report.get("status") == "pass" else 1
if __name__ == "__main__":
raise SystemExit(main())