"""Repair orchestration for signal source repair service.""" from __future__ import annotations from .errors import SignalSourceRepairMissingSignalError from .shared import ProactiveSignalCaptureService class SignalSourceRepairFlowMixin: """Runs single/batch repair orchestration.""" async def _repair_single_registry( self, *, capture_service: ProactiveSignalCaptureService, tenant_id: int, project_id: int, registry_id: int, sender: str, timeout_seconds: int, ) -> dict[str, object]: row = await self._load_registry( tenant_id=tenant_id, project_id=project_id, registry_id=registry_id, ) if row is None: return {"registry_id": int(registry_id), "status": "not_found"} if row.signal_id is not None: return self._build_item_result( row=row, signal_id=self._safe_int(row.signal_id), capture_status="already_linked", work_item_id=None, route_status="", ) reusable_signal_id = await self._find_reusable_signal_id( tenant_id=tenant_id, project_id=project_id, row=row, ) if reusable_signal_id is not None: await self._persist_registry_link( tenant_id=tenant_id, project_id=project_id, row=row, signal_id=int(reusable_signal_id), capture_status="relinked", ) return self._build_item_result( row=row, signal_id=int(reusable_signal_id), capture_status="relinked", work_item_id=None, route_status="", ) capture_result = await self._capture_registry( capture_service=capture_service, tenant_id=tenant_id, project_id=project_id, sender=sender, row=row, stage="base", timeout_seconds=timeout_seconds, ) signal_id = self._extract_signal_id(capture_result) if signal_id is None: capture_result = await self._capture_registry( capture_service=capture_service, tenant_id=tenant_id, project_id=project_id, sender=sender, row=row, stage="explicit", timeout_seconds=timeout_seconds, ) signal_id = self._extract_signal_id(capture_result) if signal_id is None: signal_id = await self._find_reusable_signal_id( tenant_id=tenant_id, project_id=project_id, row=row, ) if signal_id is None: raise SignalSourceRepairMissingSignalError( registry_id=int(row.id), project_id=int(project_id), status=str(capture_result.get("status") or ""), ) capture_status = str(capture_result.get("status") or "captured") await self._persist_registry_link( tenant_id=tenant_id, project_id=project_id, row=row, signal_id=int(signal_id), capture_status=capture_status, ) return self._build_item_result( row=row, signal_id=int(signal_id), capture_status=capture_status, work_item_id=self._safe_int(capture_result.get("work_item_id")), route_status=self._extract_route_status(capture_result), ) async def repair_registries( self, *, tenant_id: int, project_id: int, registry_ids: list[int], sender: str, ) -> list[dict[str, object]]: capture_service = ProactiveSignalCaptureService(self.db) timeout_seconds = self._resolve_timeout_seconds() results: list[dict[str, object]] = [] try: for registry_id in registry_ids: item = await self._repair_single_registry( capture_service=capture_service, tenant_id=tenant_id, project_id=project_id, registry_id=int(registry_id), sender=sender, timeout_seconds=timeout_seconds, ) results.append(item) await self.db.commit() except Exception: await self.db.rollback() raise return results