112 lines
3.6 KiB
Python
112 lines
3.6 KiB
Python
"""ARR-owned writeback pipeline for authenticated Super Agent results."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from typing import Any, Dict, Optional, Protocol
|
|
|
|
from arr_ingestion.contracts import ArtifactRef
|
|
from arr_ingestion.repository import IngestionOutcome
|
|
from arr_ingestion.service import IngestionService
|
|
from arr_processing.registration import ProcessingOutputRegistrar
|
|
from arr_processing.runner import ProcessingRunner
|
|
|
|
|
|
class SourceArtifactResolver(Protocol):
|
|
"""Resolve the immutable source registered for one ARR processing attempt."""
|
|
|
|
def source_for_attempt(self, job_id: str, attempt_no: int) -> ArtifactRef:
|
|
...
|
|
|
|
|
|
class DeliveryOutcomeResolver(Protocol):
|
|
"""Read a committed delivery without fetching its output files again."""
|
|
|
|
def outcome_for_delivery(self, delivery_id: str) -> Optional[IngestionOutcome]:
|
|
...
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class AgentWritebackReceipt:
|
|
status: str
|
|
job_id: str
|
|
business_date: Optional[str]
|
|
daily_version_id: Optional[int]
|
|
version_no: Optional[int]
|
|
callback_replayed: bool
|
|
|
|
@classmethod
|
|
def from_outcome(
|
|
cls,
|
|
outcome: IngestionOutcome,
|
|
*,
|
|
callback_replayed: bool,
|
|
) -> "AgentWritebackReceipt":
|
|
return cls(
|
|
status=outcome.status,
|
|
job_id=outcome.job_id,
|
|
business_date=(
|
|
outcome.business_date.isoformat()
|
|
if outcome.business_date is not None
|
|
else None
|
|
),
|
|
daily_version_id=outcome.daily_version_id,
|
|
version_no=outcome.version_no,
|
|
callback_replayed=callback_replayed,
|
|
)
|
|
|
|
def to_dict(self) -> Dict[str, Any]:
|
|
return {
|
|
"status": self.status,
|
|
"job_id": self.job_id,
|
|
"business_date": self.business_date,
|
|
"daily_version_id": self.daily_version_id,
|
|
"version_no": self.version_no,
|
|
"callback_replayed": self.callback_replayed,
|
|
}
|
|
|
|
|
|
class AgentResultWriteback:
|
|
"""Verify, correlate, fetch, independently validate, and atomically persist."""
|
|
|
|
def __init__(
|
|
self,
|
|
runner: ProcessingRunner,
|
|
source_resolver: SourceArtifactResolver,
|
|
output_registrar: ProcessingOutputRegistrar,
|
|
ingestion_service: IngestionService,
|
|
*,
|
|
outcome_resolver: Optional[DeliveryOutcomeResolver] = None,
|
|
) -> None:
|
|
self._runner = runner
|
|
self._source_resolver = source_resolver
|
|
self._output_registrar = output_registrar
|
|
self._ingestion_service = ingestion_service
|
|
self._outcome_resolver = outcome_resolver
|
|
|
|
def accept(self, raw_signed_result: bytes) -> AgentWritebackReceipt:
|
|
completion = self._runner.accept_callback(raw_signed_result)
|
|
result = completion.result
|
|
|
|
if completion.callback_replayed and self._outcome_resolver is not None:
|
|
existing = self._outcome_resolver.outcome_for_delivery(result.delivery_id)
|
|
if existing is not None:
|
|
return AgentWritebackReceipt.from_outcome(
|
|
existing,
|
|
callback_replayed=True,
|
|
)
|
|
|
|
source = self._source_resolver.source_for_attempt(
|
|
result.job_id,
|
|
result.attempt_no,
|
|
)
|
|
registered = self._output_registrar.register(result, source)
|
|
outcome = self._ingestion_service.ingest(registered.raw_envelope)
|
|
return AgentWritebackReceipt.from_outcome(
|
|
outcome,
|
|
callback_replayed=(
|
|
completion.callback_replayed
|
|
or outcome.status == "already_committed"
|
|
),
|
|
)
|