#!/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"m3taversal-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"m3taversal 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_m3taversal_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())
