from __future__ import annotations from types import SimpleNamespace from typing import Any import pytest from agent.orchestration import TaskStatus from script_build_host.application.recovery import MissionRecoveryService from script_build_host.domain.records import ( BuildStatus, Principal, RecoveryClassification, ) class _Repository: def __init__(self, value: Any) -> None: self.value = value async def get_by_build(self, *_args: Any, **_kwargs: Any) -> Any: return self.value async def get_status(self, _script_build_id: int) -> BuildStatus: return self.value class _Authorizer: async def require_access(self, _principal: Principal, _script_build_id: int) -> None: return None class _TaskStore: async def load(self, _root_trace_id: str) -> Any: root = SimpleNamespace(task_id="root", status=TaskStatus.RUNNING) child = SimpleNamespace(task_id="legacy-child") return SimpleNamespace( root_task_id="root", tasks={"root": root, "legacy-child": child}, operations={}, ) class _LegacyContractReader: async def contract_for_task(self, _root_trace_id: str, _task: Any) -> Any: error = RuntimeError("compiler manifest is missing") error.code = "TASK_CONTRACT_INVALID" # type: ignore[attr-defined] raise error @pytest.mark.asyncio async def test_unfinished_legacy_contract_requires_manual_reconciliation() -> None: binding = SimpleNamespace(root_trace_id="root-trace") coordinator = SimpleNamespace(task_store=_TaskStore()) service = MissionRecoveryService( coordinator=coordinator, bindings=_Repository(binding), publications=_Repository(None), legacy_state=_Repository(BuildStatus.RUNNING), authorizer=_Authorizer(), continuation=SimpleNamespace(), finalization=SimpleNamespace(), contract_reader=_LegacyContractReader(), ) result = await service.resume(900049, Principal("owner")) assert result.classification is RecoveryClassification.MANUAL_RECONCILIATION assert result.status is BuildStatus.RUNNING assert "compiler manifest" in result.detail