from __future__ import annotations

import argparse
import copy
import json
import os
import subprocess
import time
from pathlib import Path, PureWindowsPath

import pytest

from scripts import leo_behavior_manifest as behavior
from scripts import leo_identity_manifest as identity
from scripts import leo_identity_profile as profile_runtime
from scripts import run_leo_identity_reconstruction_canary as canary

ROOT = Path(__file__).resolve().parents[1]
COMMITTED_RECEIPTS = (
    ROOT / "docs/reports/leo-working-state-20260709/leo-reproducible-identity-t2-current.json",
    ROOT / "docs/reports/leo-working-state-20260709/leo-reproducible-identity-drift-negative-current.json",
)


def _write(path: Path, value: str) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(value, encoding="utf-8")


def _write_json(path: Path, value: dict) -> None:
    _write(path, json.dumps(value, indent=2, sort_keys=True) + "\n")


def _assert_path_portable_receipt(value: object) -> None:
    canary._validate_portable_receipt(value)


def _assert_logical_child_execution(child: dict, *, profile_role: str) -> None:
    logical_command = child["logical_command"]
    assert "command" not in child
    assert child["profile_role"] == profile_role
    assert child["command_serialization"] == "logical_redacted_v1"
    assert child["actual_argv_persisted"] is False
    assert logical_command[0] == "<python>"
    assert logical_command[logical_command.index("--profile") + 1] == "<temporary-profile>"
    _assert_path_portable_receipt(child)


def _fixture(tmp_path: Path) -> dict[str, Path | dict]:
    repo = tmp_path / "repo"
    profile = repo / "profile-template"
    hermes = repo / "hermes-runtime"
    compiled = tmp_path / "compiled-profile"
    _write(
        profile / "config.yaml",
        """model:
  provider: fixture-local
  default: identity-v1
  max_tokens: 512
memory:
  enabled: false
gateway:
  execution_mode: local_no_send
  telegram:
    bot_token: never-emit-this-fixture-value
transport:
  endpoint: https://fixture-user:fixture-password@example.invalid/v1
  headers: ['Authorization: Bearer fixture-secret']
tools:
  allowed: [identity_readback]
  write_enabled: false
identity_runtime:
  network_send_enabled: false
  database_write_enabled: false
  allowed_tools: [identity_readback]
""",
    )
    _write(profile / "skills" / "identity" / "SKILL.md", "# identity readback\n")
    _write(profile / "plugins" / "identity" / "__init__.py", "BOUNDARY = True\n")
    _write(profile / "bin" / "identity_readback.py", "READ_ONLY = True\n")
    _write(hermes / "run_agent.py", "RUNTIME = 'identity-v1'\n")
    _write(hermes / "agent" / "prompt_builder.py", "SOUL_IS_GENERATED = True\n")
    _write(hermes / "gateway" / "run.py", "SESSION_IS_IDENTITY = False\n")
    _write(hermes / "hermes_cli" / "tools_config.py", "TOOLS = ('identity_readback',)\n")
    _write(hermes / "tools" / "registry.py", "READ_ONLY = True\n")
    for name in (
        "leo_behavior_manifest.py",
        "leo_identity_manifest.py",
        "leo_identity_profile.py",
        "run_leo_identity_reconstruction_canary.py",
    ):
        _write(repo / "scripts" / name, (ROOT / "scripts" / name).read_text(encoding="utf-8"))

    fingerprint_path = repo / "fixtures" / "database-fingerprint.json"
    constitution_path = repo / "fixtures" / "constitution.json"
    database_identity_path = repo / "fixtures" / "database-identity.json"
    fingerprint = {
        "schema": identity.DATABASE_FINGERPRINT_SCHEMA,
        "status": "ok",
        "environment": "disposable_fixture",
        "fingerprint_sha256": "1" * 64,
        "table_rows_sha256": "2" * 64,
        "structure_sha256": "3" * 64,
        "table_count": 2,
        "total_rows": 2,
        "read_consistency": {
            "status": "stable_wal_marker",
            "before": {
                "database": "fixture",
                "database_user": "reader",
                "system_identifier": "12345",
                "wal_lsn": "0/1",
            },
            "after": {
                "database": "fixture",
                "database_user": "reader",
                "system_identifier": "12345",
                "wal_lsn": "0/1",
            },
        },
    }
    constitution = {
        "schema": identity.CONSTITUTION_SCHEMA,
        "identity_name": "Leo",
        "rules": [
            {"id": "evidence", "text": "Never use temporary session memory as canonical evidence."},
            {"id": "truth", "text": "Fail closed when a pinned identity input drifts."},
        ],
    }
    database_identity = {
        "schema": identity.DATABASE_IDENTITY_SCHEMA,
        "identity_name": "Leo",
        "database_fingerprint_sha256": "1" * 64,
        "source_provenance": {
            "mode": identity.SYNTHETIC_DATABASE_MODE,
            "canonical_authority_granted": False,
            "same_transaction_as_fingerprint": False,
            "export_receipt_sha256": None,
        },
        "records": [
            {
                "table": "public.personas",
                "row_id": "persona-1",
                "kind": "persona",
                "rank": 0,
                "text": "Leo is an evidence-bound reasoning interface.",
                "status": "active",
                "evidence_sha256": "a" * 64,
            },
            {
                "table": "public.beliefs",
                "row_id": "belief-1",
                "kind": "belief",
                "rank": 0,
                "text": "Exact provenance is stronger than plausible recollection.",
                "status": "active",
                "evidence_sha256": "b" * 64,
            },
        ],
    }
    _write_json(fingerprint_path, fingerprint)
    _write_json(constitution_path, constitution)
    _write_json(database_identity_path, database_identity)

    subprocess.run(["git", "init", "-q", str(repo)], check=True)
    subprocess.run(["git", "-C", str(repo), "config", "user.email", "test@example.com"], check=True)
    subprocess.run(["git", "-C", str(repo), "config", "user.name", "Test"], check=True)
    subprocess.run(["git", "-C", str(repo), "add", "."], check=True)
    subprocess.run(
        ["git", "-C", str(repo), "commit", "-qm", "fixture"],
        check=True,
        env={
            **dict(__import__("os").environ),
            "GIT_AUTHOR_DATE": "2026-01-01T00:00:00Z",
            "GIT_COMMITTER_DATE": "2026-01-01T00:00:00Z",
        },
    )
    behavior_manifest = behavior.build_manifest(profile, hermes, repo)
    manifest = identity.build_identity_manifest(
        behavior_manifest=behavior_manifest,
        database_fingerprint_path=fingerprint_path,
        constitution_path=constitution_path,
        database_identity_path=database_identity_path,
        source_root=repo,
    )
    return {
        "repo": repo,
        "profile": profile,
        "hermes": hermes,
        "compiled": compiled,
        "fingerprint": fingerprint_path,
        "constitution": constitution_path,
        "database_identity": database_identity_path,
        "behavior": behavior_manifest,
        "manifest": manifest,
    }


def _fully_rehash_manifest(fixture: dict[str, Path | dict], manifest: dict) -> None:
    identity_hash = behavior.canonical_sha256(manifest["identity_inputs"])
    manifest["identity_inputs_sha256"] = identity_hash
    fingerprint = identity.load_json(fixture["fingerprint"], "database fingerprint")
    rules = identity.canonical_rules(identity.load_json(fixture["constitution"], "constitution"))
    records = identity.canonical_database_records(
        identity.load_json(fixture["database_identity"], "database identity"),
        fingerprint_sha256=fingerprint["fingerprint_sha256"],
    )
    database_provenance = identity.database_identity_provenance(
        identity.load_json(fixture["database_identity"], "database identity"),
        fingerprint=fingerprint,
    )
    rendered = identity.render_identity_views(
        identity_inputs_sha256=identity_hash,
        database_fingerprint_sha256=fingerprint["fingerprint_sha256"],
        database_provenance=database_provenance,
        rules=rules,
        records=records,
    )
    for name, content in rendered.items():
        manifest["compiled_views"][name]["sha256"] = behavior.sha256_bytes(content.encode("utf-8"))
        manifest["compiled_views"][name]["generated_from_identity_inputs_sha256"] = identity_hash
    stable = {key: value for key, value in manifest.items() if key != "manifest_sha256"}
    manifest["manifest_sha256"] = behavior.canonical_sha256(stable)


def _rehash_behavior_manifest(manifest: dict) -> None:
    manifest["identity_runtime_sha256"] = behavior.canonical_sha256(behavior.identity_runtime_payload(manifest))
    manifest["static_runtime_sha256"] = behavior.canonical_sha256(behavior.static_runtime_payload(manifest))
    manifest["behavior_sha256"] = behavior.canonical_sha256(behavior.stable_manifest_payload(manifest))


def _canary_args(fixture: dict[str, Path | dict], output: Path, *, inject_drift: bool = False) -> argparse.Namespace:
    return argparse.Namespace(
        profile_template=fixture["profile"],
        hermes_root=fixture["hermes"],
        deployment_root=fixture["repo"],
        source_root=fixture["repo"],
        database_fingerprint=fixture["fingerprint"],
        constitution=fixture["constitution"],
        database_identity=fixture["database_identity"],
        output=output,
        inject_drift_before_restart=inject_drift,
    )


@pytest.mark.parametrize(
    "private_path",
    [
        "/" + "Users/operator/checkout/profile",
        "/" + "private/tmp/lane/.venv/bin/python",
        "/" + "var/folders/cache/temporary-profile",
        "/" + "tmp/temporary-profile",
        "/" + "opt/checkout/interpreter",
        "/" + "workspace/checkout/temporary-profile",
        str(PureWindowsPath("C:/operator/checkout/temporary-profile")),
        "\\\\" + "server\\share\\checkout\\temporary-profile",
    ],
)
def test_receipt_path_guard_recursively_rejects_private_and_absolute_paths(private_path: str) -> None:
    with pytest.raises(canary.CanaryError, match="private or absolute filesystem path"):
        _assert_path_portable_receipt({"outer": [{"logical_command": ["<python>", private_path]}]})


def test_receipt_path_guard_rejects_an_absolute_path_in_a_nested_key() -> None:
    private_key = "/" + "tmp/checkout/temporary-profile"
    with pytest.raises(canary.CanaryError, match="private or absolute filesystem path"):
        _assert_path_portable_receipt({"outer": [{private_key: "<temporary-profile>"}]})


def test_logical_command_uses_placeholders_for_paths_outside_the_deployment_root(tmp_path: Path) -> None:
    logical_command = canary._logical_query_command(
        deployment_root=tmp_path / "checkout",
        source_root=tmp_path / "outside-source",
        hermes_root=tmp_path / "outside-hermes",
    )

    assert logical_command[logical_command.index("--source-root") + 1] == "<source-root>"
    assert logical_command[logical_command.index("--hermes-root") + 1] == "<hermes-root>"
    _assert_path_portable_receipt(logical_command)


@pytest.mark.parametrize("receipt_path", COMMITTED_RECEIPTS, ids=lambda path: path.name)
def test_committed_identity_receipts_are_path_portable_and_self_hashed(receipt_path: Path) -> None:
    receipt = json.loads(receipt_path.read_text(encoding="utf-8"))
    _assert_path_portable_receipt(receipt)
    stable = {key: value for key, value in receipt.items() if key != "receipt_sha256"}
    assert behavior.canonical_sha256(stable) == receipt["receipt_sha256"]


def test_manifest_compiles_generated_views_and_reproduces_identity_across_queries(tmp_path: Path) -> None:
    fixture = _fixture(tmp_path)
    manifest = fixture["manifest"]
    assert isinstance(manifest, dict)
    rebuilt = identity.build_identity_manifest(
        behavior_manifest=fixture["behavior"],
        database_fingerprint_path=fixture["fingerprint"],
        constitution_path=fixture["constitution"],
        database_identity_path=fixture["database_identity"],
        source_root=fixture["repo"],
    )
    assert rebuilt == manifest

    compile_receipt = profile_runtime.compile_profile(
        manifest,
        source_root=fixture["repo"],
        profile_template=fixture["profile"],
        profile=fixture["compiled"],
        hermes_root=fixture["hermes"],
        deployment_root=fixture["repo"],
    )
    first = profile_runtime.query_profile(
        fixture["compiled"],
        query=profile_runtime.FIXED_QUERY,
        source_root=fixture["repo"],
        hermes_root=fixture["hermes"],
        deployment_root=fixture["repo"],
    )
    second = profile_runtime.query_profile(
        fixture["compiled"],
        query=profile_runtime.FIXED_QUERY,
        source_root=fixture["repo"],
        hermes_root=fixture["hermes"],
        deployment_root=fixture["repo"],
    )

    assert compile_receipt["status"] == "pass"
    assert "never-emit-this-fixture-value" not in (fixture["compiled"] / "config.yaml").read_text(encoding="utf-8")
    assert "fixture-password" not in (fixture["compiled"] / "config.yaml").read_text(encoding="utf-8")
    assert "fixture-secret" not in (fixture["compiled"] / "config.yaml").read_text(encoding="utf-8")
    assert (fixture["compiled"] / "SOUL.md").read_text(encoding="utf-8").startswith("<!-- GENERATED FILE")
    assert first["manifest_sha256"] == second["manifest_sha256"]
    assert first["identity_inputs_sha256"] == second["identity_inputs_sha256"]
    assert first["answer_sha256"] == second["answer_sha256"]
    assert first["output_provenance"] == second["output_provenance"]
    assert first["runtime_instance_id"] != second["runtime_instance_id"]
    assert first["session"]["included_in_output_provenance"] is False
    assert first["output_provenance"]["database_canonical_authority_granted"] is False
    assert first["authorization"]["authorization_decision_observed"] is False
    assert "synthetic noncanonical fixture" in first["answer"]
    assert len(list((fixture["compiled"] / "sessions").glob("*.json"))) == 2


def test_profile_and_bound_source_drift_fail_closed(tmp_path: Path) -> None:
    fixture = _fixture(tmp_path)
    profile_runtime.compile_profile(
        fixture["manifest"],
        source_root=fixture["repo"],
        profile_template=fixture["profile"],
        profile=fixture["compiled"],
        hermes_root=fixture["hermes"],
        deployment_root=fixture["repo"],
    )
    with (fixture["compiled"] / "SOUL.md").open("a", encoding="utf-8") as handle:
        handle.write("drift\n")
    with pytest.raises(identity.IdentityManifestError, match="compiled view drift detected"):
        profile_runtime.query_profile(
            fixture["compiled"],
            query=profile_runtime.FIXED_QUERY,
            source_root=fixture["repo"],
            hermes_root=fixture["hermes"],
            deployment_root=fixture["repo"],
        )

    _write(fixture["constitution"], fixture["constitution"].read_text(encoding="utf-8") + "\n")
    with pytest.raises(identity.IdentityManifestError, match="constitution source content drift"):
        identity.verify_bound_sources(fixture["manifest"], fixture["repo"])


@pytest.mark.parametrize(
    ("relative_path", "content", "message"),
    [
        ("memories/USER.md", "untrusted memory\n", "forbidden nonauthoritative"),
        ("MEMORY.md", "untrusted top-level memory\n", "forbidden nonauthoritative"),
        ("USER.md", "untrusted top-level user memory\n", "forbidden nonauthoritative"),
        ("platforms/pairing/telegram.json", "{}\n", "forbidden nonauthoritative"),
        (".env", "LEO_SECRET=untrusted\n", "profile entry set is not exact"),
        ("gateway.json", "{}\n", "profile entry set is not exact"),
        ("unexpected.txt", "untrusted input\n", "profile entry set is not exact"),
        ("sessions/injected.txt", "untrusted session\n", "unsafe session entry"),
        ("state/injected.json", "{}\n", "state directory must remain empty"),
    ],
)
def test_profile_rechecks_nonauthoritative_surfaces_before_every_query(
    tmp_path: Path, relative_path: str, content: str, message: str
) -> None:
    fixture = _fixture(tmp_path)
    profile_runtime.compile_profile(
        fixture["manifest"],
        source_root=fixture["repo"],
        profile_template=fixture["profile"],
        profile=fixture["compiled"],
        hermes_root=fixture["hermes"],
        deployment_root=fixture["repo"],
    )
    _write(fixture["compiled"] / relative_path, content)

    with pytest.raises(profile_runtime.IdentityProfileError, match=message):
        profile_runtime.query_profile(
            fixture["compiled"],
            query=profile_runtime.FIXED_QUERY,
            source_root=fixture["repo"],
            hermes_root=fixture["hermes"],
            deployment_root=fixture["repo"],
        )


def test_manifest_rejects_rehashed_core_tampering(tmp_path: Path) -> None:
    fixture = _fixture(tmp_path)
    tampered = copy.deepcopy(fixture["manifest"])
    tampered["identity_inputs"]["session_boundary"]["may_be_used_as_evidence"] = True
    stable = {key: value for key, value in tampered.items() if key != "manifest_sha256"}
    tampered["manifest_sha256"] = behavior.canonical_sha256(stable)

    with pytest.raises(identity.IdentityManifestError, match="identity input hash drift"):
        identity.validate_identity_manifest(tampered)


@pytest.mark.parametrize(
    ("path", "value", "message"),
    [
        (("permissions", "runtime_policy", "network_send_enabled"), True, "exact local readback policy"),
        (("session_boundary", "may_be_used_as_evidence"), True, "session authority boundary"),
    ],
)
def test_manifest_rejects_fully_rehashed_safety_invariant_tampering(
    tmp_path: Path, path: tuple[str, ...], value: object, message: str
) -> None:
    fixture = _fixture(tmp_path)
    tampered = copy.deepcopy(fixture["manifest"])
    target = tampered["identity_inputs"]
    for key in path[:-1]:
        target = target[key]
    target[path[-1]] = value
    _fully_rehash_manifest(fixture, tampered)

    with pytest.raises(identity.IdentityManifestError, match=message):
        identity.verify_bound_sources(tampered, fixture["repo"])


def test_behavior_manifest_rejects_unhashed_model_claim_tampering(tmp_path: Path) -> None:
    fixture = _fixture(tmp_path)
    tampered_behavior = copy.deepcopy(fixture["behavior"])
    tampered_behavior["model_runtime"]["default_model"] = "tampered-unobserved-model"

    with pytest.raises(identity.IdentityManifestError, match="behavior identity runtime hash drift"):
        identity.build_identity_manifest(
            behavior_manifest=tampered_behavior,
            database_fingerprint_path=fixture["fingerprint"],
            constitution_path=fixture["constitution"],
            database_identity_path=fixture["database_identity"],
            source_root=fixture["repo"],
        )


def test_profile_rejects_a_dangling_extra_symlink(tmp_path: Path) -> None:
    fixture = _fixture(tmp_path)
    profile_runtime.compile_profile(
        fixture["manifest"],
        source_root=fixture["repo"],
        profile_template=fixture["profile"],
        profile=fixture["compiled"],
        hermes_root=fixture["hermes"],
        deployment_root=fixture["repo"],
    )
    (fixture["compiled"] / ".env").symlink_to(tmp_path / "missing-env")

    with pytest.raises(profile_runtime.IdentityProfileError, match="profile entry set is not exact"):
        profile_runtime.query_profile(
            fixture["compiled"],
            query=profile_runtime.FIXED_QUERY,
            source_root=fixture["repo"],
            hermes_root=fixture["hermes"],
            deployment_root=fixture["repo"],
        )


def test_profile_rejects_a_symlink_in_an_allowed_entry(tmp_path: Path) -> None:
    fixture = _fixture(tmp_path)
    profile_runtime.compile_profile(
        fixture["manifest"],
        source_root=fixture["repo"],
        profile_template=fixture["profile"],
        profile=fixture["compiled"],
        hermes_root=fixture["hermes"],
        deployment_root=fixture["repo"],
    )
    external_config = tmp_path / "external-config.yaml"
    external_config.write_bytes((fixture["compiled"] / "config.yaml").read_bytes())
    (fixture["compiled"] / "config.yaml").unlink()
    (fixture["compiled"] / "config.yaml").symlink_to(external_config)

    with pytest.raises(profile_runtime.IdentityProfileError, match="profile entries must not be symlinks"):
        profile_runtime.query_profile(
            fixture["compiled"],
            query=profile_runtime.FIXED_QUERY,
            source_root=fixture["repo"],
            hermes_root=fixture["hermes"],
            deployment_root=fixture["repo"],
        )


@pytest.mark.parametrize(
    ("mutation", "message"),
    [
        ("unreadable_file", "unreadable inputs"),
        ("symlink", "unsupported symlinks"),
        ("forged_structure", "is empty"),
    ],
)
def test_behavior_manifest_rejects_unreplayable_identity_components(
    tmp_path: Path, mutation: str, message: str
) -> None:
    fixture = _fixture(tmp_path)
    tampered_behavior = copy.deepcopy(fixture["behavior"])
    content = tampered_behavior["components"]["procedural_skills"]["content"]
    if mutation == "unreadable_file":
        content["files"][0].pop("sha256")
        content["files"][0]["status"] = "unavailable"
    elif mutation == "symlink":
        content["symlinks"].append(
            {
                "path": "skills/identity/link",
                "target": "/outside/checkout",
                "target_fingerprint": {"kind": "unavailable", "error": "FileNotFoundError"},
            }
        )
    else:
        content["files"] = []
    content["sha256"] = behavior.canonical_sha256({key: content[key] for key in ("files", "missing", "symlinks")})
    _rehash_behavior_manifest(tampered_behavior)

    with pytest.raises(identity.IdentityManifestError, match=message):
        identity.validate_behavior_manifest(tampered_behavior)


def test_fully_rehashed_model_claim_must_match_observed_runtime(tmp_path: Path) -> None:
    fixture = _fixture(tmp_path)
    tampered = copy.deepcopy(fixture["manifest"])
    tampered["identity_inputs"]["model"]["default_model"] = "tampered-unobserved-model"
    _fully_rehash_manifest(fixture, tampered)
    identity.validate_identity_manifest(tampered)

    with pytest.raises(
        profile_runtime.IdentityProfileError, match="model runtime binding drift detected: default_model"
    ):
        profile_runtime.compile_profile(
            tampered,
            source_root=fixture["repo"],
            profile_template=fixture["profile"],
            profile=fixture["compiled"],
            hermes_root=fixture["hermes"],
            deployment_root=fixture["repo"],
        )
    assert not fixture["compiled"].exists()


def test_restart_canary_uses_distinct_processes_and_cleans_up(tmp_path: Path) -> None:
    fixture = _fixture(tmp_path)
    output = tmp_path / "restart-receipt.json"
    report, exit_code = canary.run_canary(_canary_args(fixture, output))

    assert exit_code == 0
    assert report["status"] == "pass"
    assert report["gates"]["restart_process_is_distinct"] is True
    assert report["gates"]["restart_profile_recompiled_from_manifest"] is True
    assert report["restart_compile"]["session_directories_started_empty"] is True
    assert report["drift_compile"]["session_directories_started_empty"] is True
    _assert_logical_child_execution(report["first_start"], profile_role="first_start")
    _assert_logical_child_execution(report["restart"], profile_role="restart")
    _assert_logical_child_execution(report["drift_negative"], profile_role="drift_negative")
    _assert_path_portable_receipt(report)
    assert report["first_start"]["launcher_pid"] != report["restart"]["launcher_pid"]
    assert report["first_start"]["process_group_absent_after_wait"] is True
    assert report["restart"]["process_group_absent_after_wait"] is True
    assert report["drift_negative"]["fail_closed"] is True
    assert report["drift_negative"]["process_group_absent_after_wait"] is True
    assert report["goal_tier_satisfied"] is True
    assert report["current_tier"] == "T2_runtime"
    assert report["cleanup"]["temporary_root_removed"] is True
    assert behavior.git_state(fixture["repo"])["worktree_clean"] is True
    assert json.loads(output.read_text(encoding="utf-8")) == report


def test_restart_canary_rejects_drift_before_second_start(tmp_path: Path) -> None:
    fixture = _fixture(tmp_path)
    output = tmp_path / "drift-receipt.json"
    report, exit_code = canary.run_canary(_canary_args(fixture, output, inject_drift=True))

    assert exit_code == 0
    assert report["status"] == "pass"
    assert report["gates"]["drift_detected_before_restart"] is True
    assert report["second_start_attempted"] is False
    assert "restart" not in report
    _assert_logical_child_execution(report["first_start"], profile_role="first_start")
    _assert_logical_child_execution(report["pre_restart_drift"], profile_role="pre_restart_drift")
    _assert_path_portable_receipt(report)
    assert report["pre_restart_drift"]["process_group_absent_after_wait"] is True
    assert all(report["gates"].values())
    assert report["goal_tier_satisfied"] is False
    assert report["current_tier"] == "T1_model"
    assert report["cleanup"]["temporary_root_removed"] is True
    assert json.loads(output.read_text(encoding="utf-8")) == report


def test_query_child_timeout_terminates_process_group(tmp_path: Path) -> None:
    fixture = _fixture(tmp_path)
    marker = tmp_path / "descendant.pid"
    sleeping_module = f"""import subprocess
import sys
import time
from pathlib import Path

child = subprocess.Popen([sys.executable, '-c', 'import time; time.sleep(60)'])
Path({str(marker)!r}).write_text(str(child.pid), encoding='utf-8')
time.sleep(60)
"""
    _write(fixture["repo"] / "scripts" / "leo_identity_profile.py", sleeping_module)

    result = canary._run_query_child(
        deployment_root=fixture["repo"],
        profile=fixture["compiled"],
        source_root=fixture["repo"],
        hermes_root=fixture["hermes"],
        profile_role="timeout_test",
        timeout_seconds=0.5,
    )

    assert result["timed_out"] is True
    assert result["terminated_with"] in {"SIGTERM", "SIGKILL"}
    assert result["returncode"] != 0
    assert result["process_group_absent_after_wait"] is True
    descendant_pid = int(marker.read_text(encoding="utf-8"))
    deadline = time.monotonic() + 5
    while time.monotonic() < deadline:
        try:
            os.kill(descendant_pid, 0)
        except ProcessLookupError:
            break
        time.sleep(0.02)
    with pytest.raises(ProcessLookupError):
        os.kill(descendant_pid, 0)


def test_query_child_cleans_and_rejects_orphan_from_completed_launcher(tmp_path: Path) -> None:
    fixture = _fixture(tmp_path)
    marker = tmp_path / "completed-descendant.pid"
    query_payload = {"schema": profile_runtime.QUERY_RECEIPT_SCHEMA, "status": "pass"}
    leaking_module = f"""import json
import subprocess
import sys
from pathlib import Path

child = subprocess.Popen(
    [sys.executable, '-c', 'import time; time.sleep(60)'],
    stdin=subprocess.DEVNULL,
    stdout=subprocess.DEVNULL,
    stderr=subprocess.DEVNULL,
)
Path({str(marker)!r}).write_text(str(child.pid), encoding='utf-8')
print(json.dumps({query_payload!r}))
"""
    _write(fixture["repo"] / "scripts" / "leo_identity_profile.py", leaking_module)

    result = canary._run_query_child(
        deployment_root=fixture["repo"],
        profile=fixture["compiled"],
        source_root=fixture["repo"],
        hermes_root=fixture["hermes"],
        profile_role="orphan_cleanup_test",
        timeout_seconds=5,
    )

    assert result["returncode"] == 0
    assert result["orphan_cleanup_required"] is True
    assert result["terminated_with"] in {"SIGTERM", "SIGKILL"}
    assert result["process_group_absent_after_wait"] is True
    assert canary._query_passed(result) is False


def test_wal_capture_marker_is_not_an_identity_input(tmp_path: Path) -> None:
    fixture = _fixture(tmp_path)
    original = fixture["manifest"]
    fingerprint = json.loads(fixture["fingerprint"].read_text(encoding="utf-8"))
    fingerprint["read_consistency"]["before"]["wal_lsn"] = "0/2"
    fingerprint["read_consistency"]["after"]["wal_lsn"] = "0/2"
    _write_json(fixture["fingerprint"], fingerprint)
    rebuilt = identity.build_identity_manifest(
        behavior_manifest=fixture["behavior"],
        database_fingerprint_path=fixture["fingerprint"],
        constitution_path=fixture["constitution"],
        database_identity_path=fixture["database_identity"],
        source_root=fixture["repo"],
    )

    assert rebuilt["identity_inputs_sha256"] == original["identity_inputs_sha256"]
    assert rebuilt["manifest_sha256"] == original["manifest_sha256"]


def test_database_identity_and_system_markers_are_identity_inputs(tmp_path: Path) -> None:
    fixture = _fixture(tmp_path)
    original = fixture["manifest"]
    fingerprint = json.loads(fixture["fingerprint"].read_text(encoding="utf-8"))
    for marker in (fingerprint["read_consistency"]["before"], fingerprint["read_consistency"]["after"]):
        marker["database"] = "different_database"
        marker["database_user"] = "different_reader"
        marker["system_identifier"] = "99999"
    _write_json(fixture["fingerprint"], fingerprint)
    rebuilt = identity.build_identity_manifest(
        behavior_manifest=fixture["behavior"],
        database_fingerprint_path=fixture["fingerprint"],
        constitution_path=fixture["constitution"],
        database_identity_path=fixture["database_identity"],
        source_root=fixture["repo"],
    )

    assert rebuilt["identity_inputs_sha256"] != original["identity_inputs_sha256"]
    with pytest.raises(identity.IdentityManifestError, match="database fingerprint semantic drift"):
        identity.verify_bound_sources(original, fixture["repo"])


def test_synthetic_database_rows_cannot_claim_canonical_authority(tmp_path: Path) -> None:
    fixture = _fixture(tmp_path)
    database_identity = json.loads(fixture["database_identity"].read_text(encoding="utf-8"))
    database_identity["source_provenance"] = {
        "mode": identity.CANONICAL_DATABASE_MODE,
        "canonical_authority_granted": True,
        "same_transaction_as_fingerprint": True,
        "export_receipt_sha256": "f" * 64,
    }
    _write_json(fixture["database_identity"], database_identity)

    with pytest.raises(identity.IdentityManifestError, match="independently verified output"):
        identity.build_identity_manifest(
            behavior_manifest=fixture["behavior"],
            database_fingerprint_path=fixture["fingerprint"],
            constitution_path=fixture["constitution"],
            database_identity_path=fixture["database_identity"],
            source_root=fixture["repo"],
        )


def test_self_hashed_database_export_receipt_cannot_grant_canonical_authority(tmp_path: Path) -> None:
    fixture = _fixture(tmp_path)
    fingerprint = json.loads(fixture["fingerprint"].read_text(encoding="utf-8"))
    fingerprint["environment"] = "canonical_readonly_capture"
    _write_json(fixture["fingerprint"], fingerprint)
    database_identity = json.loads(fixture["database_identity"].read_text(encoding="utf-8"))
    records = identity.canonical_database_records(
        database_identity,
        fingerprint_sha256=fingerprint["fingerprint_sha256"],
    )
    marker = fingerprint["read_consistency"]["before"]
    receipt_stable = {
        "schema": "livingip.untrustedCallerSuppliedExportReceipt.v1",
        "read_only": True,
        "same_transaction_as_fingerprint": True,
        "transaction_isolation": "repeatable_read_read_only",
        "database": marker["database"],
        "database_user": marker["database_user"],
        "system_identifier": marker["system_identifier"],
        "database_fingerprint_sha256": fingerprint["fingerprint_sha256"],
        "records_sha256": behavior.canonical_sha256(records),
    }
    receipt_hash = behavior.canonical_sha256(receipt_stable)
    database_identity["source_provenance"] = {
        "mode": identity.CANONICAL_DATABASE_MODE,
        "canonical_authority_granted": True,
        "same_transaction_as_fingerprint": True,
        "export_receipt_sha256": receipt_hash,
    }
    database_identity["export_receipt"] = {**receipt_stable, "receipt_sha256": receipt_hash}
    _write_json(fixture["database_identity"], database_identity)

    with pytest.raises(identity.IdentityManifestError, match="independently verified output"):
        identity.build_identity_manifest(
            behavior_manifest=fixture["behavior"],
            database_fingerprint_path=fixture["fingerprint"],
            constitution_path=fixture["constitution"],
            database_identity_path=fixture["database_identity"],
            source_root=fixture["repo"],
        )


def test_same_clean_commit_reproduces_identity_from_different_checkout_paths(tmp_path: Path) -> None:
    first = _fixture(tmp_path / "checkout-a")
    second = _fixture(tmp_path / "checkout-b")

    assert (
        first["behavior"]["teleo_infrastructure_runtime"]["git_head"]
        == second["behavior"]["teleo_infrastructure_runtime"]["git_head"]
    )
    assert first["behavior"]["identity_runtime_sha256"] == second["behavior"]["identity_runtime_sha256"]
    assert first["manifest"]["identity_inputs_sha256"] == second["manifest"]["identity_inputs_sha256"]
    assert first["manifest"]["manifest_sha256"] == second["manifest"]["manifest_sha256"]
