"""Gate 9A deterministic real-repository benchmark harness.

The benchmark creates small local repository fixtures under the requested state
directory, copies each task into an isolated worktree, applies only fixed
deterministic task handlers, runs fixed verifiers, and records trace evidence.
It does not mutate the main checkout or add runtime authority.
"""

from __future__ import annotations

from dataclasses import dataclass, field
import json
from pathlib import Path
import shutil
import subprocess
import sys
from typing import Any

from .ledger import canonical_json, stable_hash


REQUIRED_GATE9A_TASK_TYPES = (
    "import_error",
    "wrong_symbol",
    "bad_config_default",
    "data_shape_mismatch",
    "small_refactor",
    "test_addition",
    "documentation_update",
    "read_only_investigation",
    "memory_reuse_task",
    "skill_reuse_task",
    "patch_proposal_task",
    "rollback_task",
    "false_trigger_task",
    "quarantine_task",
)

MUTATING_GATE9A_TASK_TYPES = {
    "import_error",
    "wrong_symbol",
    "bad_config_default",
    "data_shape_mismatch",
    "small_refactor",
    "test_addition",
    "documentation_update",
    "memory_reuse_task",
    "skill_reuse_task",
    "patch_proposal_task",
    "rollback_task",
    "quarantine_task",
}


@dataclass(frozen=True, slots=True)
class RealRepoFixtureSpec:
    fixture_id: str
    project_name: str
    family: str

    def to_dict(self) -> dict[str, Any]:
        return {
            "fixture_id": self.fixture_id,
            "project_name": self.project_name,
            "family": self.family,
        }

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> "RealRepoFixtureSpec":
        return cls(
            fixture_id=str(data["fixture_id"]),
            project_name=str(data["project_name"]),
            family=str(data["family"]),
        )


@dataclass(frozen=True, slots=True)
class RealRepoBenchmarkTask:
    task_id: str
    fixture_id: str
    task_type: str
    description: str
    mutating: bool

    def to_dict(self) -> dict[str, Any]:
        return {
            "task_id": self.task_id,
            "fixture_id": self.fixture_id,
            "task_type": self.task_type,
            "description": self.description,
            "mutating": self.mutating,
        }

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> "RealRepoBenchmarkTask":
        return cls(
            task_id=str(data["task_id"]),
            fixture_id=str(data["fixture_id"]),
            task_type=str(data["task_type"]),
            description=str(data["description"]),
            mutating=bool(data["mutating"]),
        )


@dataclass(slots=True)
class RealRepoTaskTrace:
    trace_id: str
    task_id: str
    fixture_id: str
    task_type: str
    operations: list[str] = field(default_factory=list)
    verifier_command: list[str] = field(default_factory=list)

    def to_dict(self) -> dict[str, Any]:
        return {
            "trace_id": self.trace_id,
            "task_id": self.task_id,
            "fixture_id": self.fixture_id,
            "task_type": self.task_type,
            "operations": list(self.operations),
            "verifier_command": list(self.verifier_command),
        }

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> "RealRepoTaskTrace":
        return cls(
            trace_id=str(data["trace_id"]),
            task_id=str(data["task_id"]),
            fixture_id=str(data["fixture_id"]),
            task_type=str(data["task_type"]),
            operations=[str(item) for item in data.get("operations", [])],
            verifier_command=[str(item) for item in data.get("verifier_command", [])],
        )


@dataclass(slots=True)
class RealRepoTaskResult:
    task: RealRepoBenchmarkTask
    success: bool
    worktree_isolated: bool
    source_fixture_hash_before: str
    source_fixture_hash_after: str
    verifier_ran: bool
    verifier_passed: bool
    verifier_after_mutation: bool
    trace_recorded: bool
    changed_files: list[str]
    rollback_performed: bool
    main_checkout_mutated: bool
    trace: RealRepoTaskTrace
    verifier_output: str

    def to_dict(self) -> dict[str, Any]:
        return {
            "task": self.task.to_dict(),
            "success": self.success,
            "worktree_isolated": self.worktree_isolated,
            "source_fixture_hash_before": self.source_fixture_hash_before,
            "source_fixture_hash_after": self.source_fixture_hash_after,
            "verifier_ran": self.verifier_ran,
            "verifier_passed": self.verifier_passed,
            "verifier_after_mutation": self.verifier_after_mutation,
            "trace_recorded": self.trace_recorded,
            "changed_files": list(self.changed_files),
            "rollback_performed": self.rollback_performed,
            "main_checkout_mutated": self.main_checkout_mutated,
            "trace": self.trace.to_dict(),
            "verifier_output": self.verifier_output,
        }

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> "RealRepoTaskResult":
        return cls(
            task=RealRepoBenchmarkTask.from_dict(dict(data["task"])),
            success=bool(data["success"]),
            worktree_isolated=bool(data["worktree_isolated"]),
            source_fixture_hash_before=str(data["source_fixture_hash_before"]),
            source_fixture_hash_after=str(data["source_fixture_hash_after"]),
            verifier_ran=bool(data["verifier_ran"]),
            verifier_passed=bool(data["verifier_passed"]),
            verifier_after_mutation=bool(data["verifier_after_mutation"]),
            trace_recorded=bool(data["trace_recorded"]),
            changed_files=[str(item) for item in data.get("changed_files", [])],
            rollback_performed=bool(data["rollback_performed"]),
            main_checkout_mutated=bool(data["main_checkout_mutated"]),
            trace=RealRepoTaskTrace.from_dict(dict(data["trace"])),
            verifier_output=str(data.get("verifier_output", "")),
        )


@dataclass(slots=True)
class RealRepoBenchmarkReport:
    fixture_repos: list[RealRepoFixtureSpec]
    tasks: list[RealRepoBenchmarkTask]
    results: list[RealRepoTaskResult]
    task_type_counts: dict[str, int]
    fixture_hashes_before: dict[str, str]
    fixture_hashes_after: dict[str, str]
    trace_path: str
    manifest_path: str
    success_rate: float
    worktree_isolation_rate: float
    verifier_after_mutation_rate: float
    trace_coverage: float
    regression_rate: float
    main_checkout_mutation_count: int
    no_new_runtime_authority: bool = True
    no_training_started: bool = True
    no_external_api_dependency: bool = True
    no_background_daemon_enabled: bool = True

    def to_dict(self) -> dict[str, Any]:
        return {
            "fixture_repos": [fixture.to_dict() for fixture in self.fixture_repos],
            "tasks": [task.to_dict() for task in self.tasks],
            "results": [result.to_dict() for result in self.results],
            "task_type_counts": dict(self.task_type_counts),
            "fixture_hashes_before": dict(self.fixture_hashes_before),
            "fixture_hashes_after": dict(self.fixture_hashes_after),
            "trace_path": self.trace_path,
            "manifest_path": self.manifest_path,
            "success_rate": self.success_rate,
            "worktree_isolation_rate": self.worktree_isolation_rate,
            "verifier_after_mutation_rate": self.verifier_after_mutation_rate,
            "trace_coverage": self.trace_coverage,
            "regression_rate": self.regression_rate,
            "main_checkout_mutation_count": self.main_checkout_mutation_count,
            "no_new_runtime_authority": self.no_new_runtime_authority,
            "no_training_started": self.no_training_started,
            "no_external_api_dependency": self.no_external_api_dependency,
            "no_background_daemon_enabled": self.no_background_daemon_enabled,
        }

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> "RealRepoBenchmarkReport":
        return cls(
            fixture_repos=[RealRepoFixtureSpec.from_dict(dict(item)) for item in data.get("fixture_repos", [])],
            tasks=[RealRepoBenchmarkTask.from_dict(dict(item)) for item in data.get("tasks", [])],
            results=[RealRepoTaskResult.from_dict(dict(item)) for item in data.get("results", [])],
            task_type_counts={str(key): int(value) for key, value in dict(data.get("task_type_counts", {})).items()},
            fixture_hashes_before={str(key): str(value) for key, value in dict(data.get("fixture_hashes_before", {})).items()},
            fixture_hashes_after={str(key): str(value) for key, value in dict(data.get("fixture_hashes_after", {})).items()},
            trace_path=str(data["trace_path"]),
            manifest_path=str(data["manifest_path"]),
            success_rate=float(data["success_rate"]),
            worktree_isolation_rate=float(data["worktree_isolation_rate"]),
            verifier_after_mutation_rate=float(data["verifier_after_mutation_rate"]),
            trace_coverage=float(data["trace_coverage"]),
            regression_rate=float(data["regression_rate"]),
            main_checkout_mutation_count=int(data["main_checkout_mutation_count"]),
            no_new_runtime_authority=bool(data["no_new_runtime_authority"]),
            no_training_started=bool(data["no_training_started"]),
            no_external_api_dependency=bool(data["no_external_api_dependency"]),
            no_background_daemon_enabled=bool(data["no_background_daemon_enabled"]),
        )


def default_gate9a_fixture_specs() -> list[RealRepoFixtureSpec]:
    return [
        RealRepoFixtureSpec("fixture_api_service", "api_service", "service"),
        RealRepoFixtureSpec("fixture_cli_tool", "cli_tool", "cli"),
        RealRepoFixtureSpec("fixture_data_pipeline", "data_pipeline", "data"),
        RealRepoFixtureSpec("fixture_config_app", "config_app", "config"),
        RealRepoFixtureSpec("fixture_docs_package", "docs_package", "docs"),
    ]


def default_gate9a_tasks(fixtures: list[RealRepoFixtureSpec]) -> list[RealRepoBenchmarkTask]:
    tasks: list[RealRepoBenchmarkTask] = []
    for fixture_index, fixture in enumerate(fixtures):
        for offset in range(10):
            task_type = REQUIRED_GATE9A_TASK_TYPES[(fixture_index * 10 + offset) % len(REQUIRED_GATE9A_TASK_TYPES)]
            tasks.append(
                RealRepoBenchmarkTask(
                    task_id=f"gate9a_{fixture.fixture_id}_{offset:02d}_{task_type}",
                    fixture_id=fixture.fixture_id,
                    task_type=task_type,
                    description=f"Run deterministic {task_type.replace('_', ' ')} benchmark on {fixture.project_name}.",
                    mutating=task_type in MUTATING_GATE9A_TASK_TYPES,
                )
            )
    return tasks


def run_real_repo_benchmark(state_dir: str | Path, main_checkout_root: str | Path | None = None) -> RealRepoBenchmarkReport:
    root = Path(state_dir)
    if root.exists():
        shutil.rmtree(root)
    fixtures_root = root / "fixtures"
    worktrees_root = root / "worktrees"
    traces_root = root / "traces"
    fixtures_root.mkdir(parents=True, exist_ok=True)
    worktrees_root.mkdir(parents=True, exist_ok=True)
    traces_root.mkdir(parents=True, exist_ok=True)

    checkout_root = Path(main_checkout_root or Path.cwd()).resolve()
    main_before = _main_checkout_status(checkout_root)
    fixtures = default_gate9a_fixture_specs()
    fixture_paths = {fixture.fixture_id: _write_fixture_repo(fixtures_root, fixture) for fixture in fixtures}
    fixture_hashes_before = {fixture_id: _tree_hash(path) for fixture_id, path in fixture_paths.items()}
    tasks = default_gate9a_tasks(fixtures)
    results: list[RealRepoTaskResult] = []
    trace_path = traces_root / "real_repo_benchmark_trace.jsonl"

    for task in tasks:
        source_root = fixture_paths[task.fixture_id]
        worktree_root = worktrees_root / task.task_id
        shutil.copytree(source_root, worktree_root)
        result = _run_real_repo_task(task, source_root, worktree_root, root)
        results.append(result)

    fixture_hashes_after = {fixture_id: _tree_hash(path) for fixture_id, path in fixture_paths.items()}
    main_after = _main_checkout_status(checkout_root)
    main_checkout_mutation_count = 0 if main_before == main_after else 1
    for result in results:
        result.main_checkout_mutated = bool(main_checkout_mutation_count)

    _write_jsonl(trace_path, [result.trace.to_dict() for result in results])
    task_type_counts: dict[str, int] = {}
    for task in tasks:
        task_type_counts[task.task_type] = task_type_counts.get(task.task_type, 0) + 1
    mutating_results = [result for result in results if result.task.mutating]
    success_rate = _ratio(sum(1 for result in results if result.success), len(results))
    worktree_isolation_rate = _ratio(sum(1 for result in results if result.worktree_isolated), len(results))
    verifier_after_mutation_rate = _ratio(
        sum(1 for result in mutating_results if result.verifier_after_mutation),
        len(mutating_results),
    )
    trace_coverage = _ratio(sum(1 for result in results if result.trace_recorded), len(results))
    regression_rate = 0.0 if success_rate == 1.0 and fixture_hashes_before == fixture_hashes_after else 1.0 - success_rate
    manifest_path = root / "real_repo_benchmark_manifest.json"
    report = RealRepoBenchmarkReport(
        fixture_repos=fixtures,
        tasks=tasks,
        results=results,
        task_type_counts=task_type_counts,
        fixture_hashes_before=fixture_hashes_before,
        fixture_hashes_after=fixture_hashes_after,
        trace_path=str(trace_path),
        manifest_path=str(manifest_path),
        success_rate=success_rate,
        worktree_isolation_rate=worktree_isolation_rate,
        verifier_after_mutation_rate=verifier_after_mutation_rate,
        trace_coverage=trace_coverage,
        regression_rate=regression_rate,
        main_checkout_mutation_count=main_checkout_mutation_count,
    )
    manifest_path.write_text(canonical_json(report.to_dict()), encoding="utf-8")
    return report


def _run_real_repo_task(task: RealRepoBenchmarkTask, source_root: Path, worktree_root: Path, state_root: Path) -> RealRepoTaskResult:
    source_hash_before = _tree_hash(source_root)
    before_hashes = _file_hashes(worktree_root)
    operations = [f"prepare:{task.task_type}"]
    rollback_performed = False

    _inject_task_issue(worktree_root, task)
    operations.append("inject_fixture_issue")
    pre_action_hashes = _file_hashes(worktree_root)
    rollback_snapshot = dict(pre_action_hashes)
    action_operations, rollback_performed = _apply_task_action(worktree_root, task, rollback_snapshot)
    operations.extend(action_operations)
    verifier_command = [sys.executable, "test_runner.py", task.task_type]
    verifier = subprocess.run(
        verifier_command,
        cwd=worktree_root,
        text=True,
        stdout=subprocess.PIPE,
        stderr=subprocess.STDOUT,
        timeout=10,
        check=False,
    )
    operations.append("run_fixed_verifier")
    after_hashes = _file_hashes(worktree_root)
    changed_files = sorted(relative for relative in set(before_hashes) | set(after_hashes) if before_hashes.get(relative) != after_hashes.get(relative))
    worktree_isolated = worktree_root.resolve().is_relative_to((state_root / "worktrees").resolve()) and source_root.resolve() != worktree_root.resolve()
    source_hash_after = _tree_hash(source_root)
    trace_payload = {
        "task": task.to_dict(),
        "operations": operations,
        "changed_files": changed_files,
        "verifier_returncode": verifier.returncode,
        "source_hash_before": source_hash_before,
        "source_hash_after": source_hash_after,
    }
    trace_id = stable_hash(trace_payload)
    trace = RealRepoTaskTrace(
        trace_id=trace_id,
        task_id=task.task_id,
        fixture_id=task.fixture_id,
        task_type=task.task_type,
        operations=operations,
        verifier_command=["python", "test_runner.py", task.task_type],
    )
    verifier_passed = verifier.returncode == 0
    return RealRepoTaskResult(
        task=task,
        success=verifier_passed and worktree_isolated and source_hash_before == source_hash_after,
        worktree_isolated=worktree_isolated,
        source_fixture_hash_before=source_hash_before,
        source_fixture_hash_after=source_hash_after,
        verifier_ran=True,
        verifier_passed=verifier_passed,
        verifier_after_mutation=task.mutating and verifier_passed,
        trace_recorded=bool(trace_id),
        changed_files=changed_files,
        rollback_performed=rollback_performed,
        main_checkout_mutated=False,
        trace=trace,
        verifier_output=verifier.stdout[-2000:],
    )


def _write_fixture_repo(fixtures_root: Path, fixture: RealRepoFixtureSpec) -> Path:
    repo = fixtures_root / fixture.fixture_id
    package = repo / fixture.project_name
    package.mkdir(parents=True, exist_ok=True)
    (repo / "README.md").write_text(f"# {fixture.project_name}\n\nLocal deterministic fixture for Gate 9A.\n", encoding="utf-8")
    (package / "__init__.py").write_text("from .project import new_symbol, normalize\n", encoding="utf-8")
    (package / "project.py").write_text(
        "\n".join(
            [
                "def new_symbol(value):",
                "    return f'new:{value}'",
                "",
                "def normalize(value):",
                "    return str(value).strip().lower()",
                "",
                "def service_value():",
                "    return 'service-ready'",
                "",
            ]
        ),
        encoding="utf-8",
    )
    (repo / "app.py").write_text(
        "\n".join(
            [
                f"from {fixture.project_name} import new_symbol",
                "",
                "def run(value='ok'):",
                "    return new_symbol(value)",
                "",
            ]
        ),
        encoding="utf-8",
    )
    (repo / "config.py").write_text("DEFAULT_TIMEOUT = 30\nFEATURE_ENABLED = True\n", encoding="utf-8")
    (repo / "data.json").write_text(canonical_json({"records": [{"id": 1, "name": "alpha"}]}), encoding="utf-8")
    (repo / "memory_cards.json").write_text(canonical_json([{"memory_id": "mem-normalize", "hint": "use normalize"}]), encoding="utf-8")
    (repo / "skills.json").write_text(canonical_json({"skills": [{"skill_id": "safe-normalize", "status": "active"}]}), encoding="utf-8")
    (repo / "test_runner.py").write_text(_fixture_test_runner_source(fixture.project_name), encoding="utf-8")
    return repo


def _inject_task_issue(worktree_root: Path, task: RealRepoBenchmarkTask) -> None:
    package_name = _package_name(worktree_root)
    if task.task_type == "import_error":
        (worktree_root / "app.py").write_text("from missing_service import new_symbol\n\ndef run(value='ok'):\n    return new_symbol(value)\n", encoding="utf-8")
    elif task.task_type == "wrong_symbol":
        (worktree_root / "app.py").write_text(
            f"from {package_name}.project import old_symbol\n\ndef run(value='ok'):\n    return old_symbol(value)\n",
            encoding="utf-8",
        )
    elif task.task_type == "bad_config_default":
        (worktree_root / "config.py").write_text("DEFAULT_TIMEOUT = 0\nFEATURE_ENABLED = True\n", encoding="utf-8")
    elif task.task_type == "data_shape_mismatch":
        (worktree_root / "data.json").write_text(canonical_json([{"id": 1, "name": "alpha"}]), encoding="utf-8")
    elif task.task_type == "small_refactor":
        project_path = worktree_root / package_name / "project.py"
        project_path.write_text(project_path.read_text(encoding="utf-8") + "\ndef display_name(value):\n    return str(value).strip().lower()\n", encoding="utf-8")
    elif task.task_type == "test_addition":
        _remove_if_exists(worktree_root / "tests" / "test_contract.py")
    elif task.task_type == "documentation_update":
        (worktree_root / "README.md").write_text(f"# {package_name}\n\nLocal deterministic fixture for Gate 9A.\n", encoding="utf-8")
    elif task.task_type == "memory_reuse_task":
        _remove_if_exists(worktree_root / "memory_reuse_applied.json")
    elif task.task_type == "skill_reuse_task":
        _remove_if_exists(worktree_root / "skill_reuse_applied.json")
    elif task.task_type == "patch_proposal_task":
        shutil.rmtree(worktree_root / "proposals", ignore_errors=True)
    elif task.task_type == "rollback_task":
        _remove_if_exists(worktree_root / "rollback_report.json")
    elif task.task_type == "quarantine_task":
        (worktree_root / "skills.json").write_text(canonical_json({"skills": [{"skill_id": "unsafe-shell", "status": "active"}]}), encoding="utf-8")


def _apply_task_action(worktree_root: Path, task: RealRepoBenchmarkTask, rollback_snapshot: dict[str, str]) -> tuple[list[str], bool]:
    package_name = _package_name(worktree_root)
    operations: list[str] = []
    rollback_performed = False
    if task.task_type in {"import_error", "wrong_symbol"}:
        (worktree_root / "app.py").write_text(
            f"from {package_name}.project import new_symbol\n\ndef run(value='ok'):\n    return new_symbol(value)\n",
            encoding="utf-8",
        )
        operations.append("apply_import_or_symbol_fix")
    elif task.task_type == "bad_config_default":
        (worktree_root / "config.py").write_text("DEFAULT_TIMEOUT = 30\nFEATURE_ENABLED = True\n", encoding="utf-8")
        operations.append("apply_config_default_fix")
    elif task.task_type == "data_shape_mismatch":
        (worktree_root / "data.json").write_text(canonical_json({"records": [{"id": 1, "name": "alpha"}]}), encoding="utf-8")
        operations.append("apply_data_shape_fix")
    elif task.task_type == "small_refactor":
        project_path = worktree_root / package_name / "project.py"
        text = project_path.read_text(encoding="utf-8")
        text = text.replace("def display_name(value):\n    return str(value).strip().lower()\n", "def display_name(value):\n    return normalize(value)\n")
        project_path.write_text(text, encoding="utf-8")
        operations.append("apply_small_refactor")
    elif task.task_type == "test_addition":
        tests_dir = worktree_root / "tests"
        tests_dir.mkdir(exist_ok=True)
        (tests_dir / "test_contract.py").write_text("from app import run\n\nassert run('ok') == 'new:ok'\n", encoding="utf-8")
        operations.append("add_contract_test")
    elif task.task_type == "documentation_update":
        readme = worktree_root / "README.md"
        readme.write_text(readme.read_text(encoding="utf-8") + "\n## Gate 9A\n\nDeterministic real repository benchmark fixture.\n", encoding="utf-8")
        operations.append("update_documentation")
    elif task.task_type == "read_only_investigation":
        _ = (worktree_root / "README.md").read_text(encoding="utf-8")
        _ = (worktree_root / "app.py").read_text(encoding="utf-8")
        operations.append("read_only_inspection")
    elif task.task_type == "memory_reuse_task":
        cards = json.loads((worktree_root / "memory_cards.json").read_text(encoding="utf-8"))
        (worktree_root / "memory_reuse_applied.json").write_text(canonical_json({"used_memory_id": cards[0]["memory_id"]}), encoding="utf-8")
        operations.append("apply_memory_reuse_evidence")
    elif task.task_type == "skill_reuse_task":
        skills = json.loads((worktree_root / "skills.json").read_text(encoding="utf-8"))
        (worktree_root / "skill_reuse_applied.json").write_text(canonical_json({"used_skill_id": skills["skills"][0]["skill_id"]}), encoding="utf-8")
        operations.append("apply_skill_reuse_evidence")
    elif task.task_type == "patch_proposal_task":
        proposals = worktree_root / "proposals"
        proposals.mkdir(exist_ok=True)
        (proposals / "patch_proposal.json").write_text(
            canonical_json({"candidate_id": "gate9a_patch_proposal", "changed_files": ["app.py"], "apply_mode": "proposal_only"}),
            encoding="utf-8",
        )
        operations.append("write_patch_proposal_only")
    elif task.task_type == "rollback_task":
        app_path = worktree_root / "app.py"
        original = app_path.read_text(encoding="utf-8")
        app_path.write_text("BROKEN = True\n", encoding="utf-8")
        app_path.write_text(original, encoding="utf-8")
        rollback_performed = _file_hashes(worktree_root) == rollback_snapshot
        (worktree_root / "rollback_report.json").write_text(canonical_json({"rollback_performed": rollback_performed}), encoding="utf-8")
        operations.append("apply_and_rollback_bad_change")
    elif task.task_type == "false_trigger_task":
        operations.append("reject_false_trigger_without_mutation")
    elif task.task_type == "quarantine_task":
        (worktree_root / "skills.json").write_text(canonical_json({"skills": [{"skill_id": "unsafe-shell", "status": "quarantined"}]}), encoding="utf-8")
        operations.append("quarantine_unsafe_skill")
    return operations, rollback_performed


def _fixture_test_runner_source(package_name: str) -> str:
    return f'''from __future__ import annotations

import importlib
import json
from pathlib import Path
import sys


ROOT = Path(__file__).resolve().parent


def main(task_type: str) -> int:
    if task_type in {{"import_error", "wrong_symbol"}}:
        app = importlib.import_module("app")
        assert app.run("ok") == "new:ok"
    elif task_type == "bad_config_default":
        config = importlib.import_module("config")
        assert config.DEFAULT_TIMEOUT == 30
    elif task_type == "data_shape_mismatch":
        payload = json.loads((ROOT / "data.json").read_text(encoding="utf-8"))
        assert isinstance(payload, dict)
        assert isinstance(payload.get("records"), list)
    elif task_type == "small_refactor":
        project = importlib.import_module("{package_name}.project")
        assert project.display_name(" Alpha ") == "alpha"
        assert "return normalize(value)" in (ROOT / "{package_name}" / "project.py").read_text(encoding="utf-8")
    elif task_type == "test_addition":
        assert (ROOT / "tests" / "test_contract.py").exists()
    elif task_type == "documentation_update":
        assert "Deterministic real repository benchmark fixture." in (ROOT / "README.md").read_text(encoding="utf-8")
    elif task_type == "read_only_investigation":
        assert "Gate 9A" in (ROOT / "README.md").read_text(encoding="utf-8")
        assert "def run" in (ROOT / "app.py").read_text(encoding="utf-8")
    elif task_type == "memory_reuse_task":
        payload = json.loads((ROOT / "memory_reuse_applied.json").read_text(encoding="utf-8"))
        assert payload["used_memory_id"] == "mem-normalize"
    elif task_type == "skill_reuse_task":
        payload = json.loads((ROOT / "skill_reuse_applied.json").read_text(encoding="utf-8"))
        assert payload["used_skill_id"] == "safe-normalize"
    elif task_type == "patch_proposal_task":
        payload = json.loads((ROOT / "proposals" / "patch_proposal.json").read_text(encoding="utf-8"))
        assert payload["apply_mode"] == "proposal_only"
    elif task_type == "rollback_task":
        payload = json.loads((ROOT / "rollback_report.json").read_text(encoding="utf-8"))
        assert payload["rollback_performed"] is True
        app = importlib.import_module("app")
        assert app.run("ok") == "new:ok"
    elif task_type == "false_trigger_task":
        assert not (ROOT / "proposals" / "patch_proposal.json").exists()
        assert not (ROOT / "memory_reuse_applied.json").exists()
    elif task_type == "quarantine_task":
        payload = json.loads((ROOT / "skills.json").read_text(encoding="utf-8"))
        assert payload["skills"][0]["status"] == "quarantined"
    else:
        raise AssertionError(f"unknown task type: {{task_type}}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main(sys.argv[1]))
'''


def _write_jsonl(path: Path, rows: list[dict[str, Any]]) -> None:
    path.write_text("".join(f"{canonical_json(row)}\n" for row in rows), encoding="utf-8")


def _tree_hash(root: Path) -> str:
    return stable_hash(_file_hashes(root))


def _file_hashes(root: Path) -> dict[str, str]:
    hashes: dict[str, str] = {}
    for path in sorted(root.rglob("*")):
        if not path.is_file() or "__pycache__" in path.parts or path.suffix == ".pyc":
            continue
        relative = path.relative_to(root).as_posix()
        hashes[relative] = stable_hash(path.read_text(encoding="utf-8"))
    return hashes


def _package_name(worktree_root: Path) -> str:
    candidates = [path.name for path in worktree_root.iterdir() if path.is_dir() and (path / "project.py").exists()]
    if len(candidates) != 1:
        raise ValueError(f"expected one package directory in {worktree_root}, got {candidates}")
    return candidates[0]


def _remove_if_exists(path: Path) -> None:
    if path.is_dir():
        shutil.rmtree(path)
    elif path.exists():
        path.unlink()


def _ratio(numerator: int, denominator: int) -> float:
    if denominator == 0:
        return 0.0
    return round(numerator / denominator, 6)


def _main_checkout_status(root: Path) -> str:
    try:
        result = subprocess.run(
            ["git", "status", "--porcelain=v1", "--untracked-files=all"],
            cwd=root,
            text=True,
            stdout=subprocess.PIPE,
            stderr=subprocess.DEVNULL,
            timeout=10,
            check=False,
        )
    except (OSError, subprocess.SubprocessError):
        return "git-status-unavailable"
    return result.stdout
