from __future__ import annotations import argparse import contextlib import hashlib import io import json import tempfile import unittest from datetime import date, datetime, timedelta, timezone from pathlib import Path from typing import Any from arr_ingestion.contracts import XLSX_MIME from arr_ingestion.direct_contracts import SubmissionGrant from arr_ingestion.repository import InMemoryIngestionRepository from arr_ingestion.service import IngestionService from arr_ingestion.validation import DeliveryValidator from arr_processing.callbacks import AgentResultWriteback from arr_processing.contracts import ProcessingRequest, ProcessingResult from arr_processing.ledger import InMemoryProcessingLedger from arr_processing.registration import ProcessingOutputRegistrar from arr_processing.runner import ProcessingRunner, RemoteRunSnapshot from arr_processing.signatures import SignedResultCodec from arr_storage.filesystem import FilesystemObjectBackend from arr_storage.contracts import ObjectAddress from arr_storage.store import ManagedObjectStore from arr_web.legacy_agent_services import ObjectStoreUploadCoordinator from tests.test_arr_ingestion_validation import policy from tests.test_arr_opera_daily_ingest import ( core, success_xml, ) NOW = datetime(2026, 7, 28, 9, 0, tzinfo=timezone.utc) SIGNING_KEY = b"fake-superagent-signing-key-at-least-32-bytes" class CapturingRepository: def __init__(self) -> None: self.inner = InMemoryIngestionRepository() self.registration: Any = None def register_job(self, registration: Any) -> None: self.registration = registration self.inner.register_job(registration) def issue_grant( self, job_id: str, attempt_no: int, *, ttl_seconds: int, ) -> SubmissionGrant: return SubmissionGrant( "G" * 43, job_id, attempt_no, NOW + timedelta(seconds=ttl_seconds), ) def commit_delivery(self, delivery: Any) -> Any: return self.inner.commit_delivery(delivery) class FakeSuperAgentTransport: """Fetches one opaque source handle, invokes the real Skill, and signs handles.""" def __init__( self, root: Path, store: ManagedObjectStore, codec: SignedResultCodec, ) -> None: self.root = root self.store = store self.codec = codec self.remote_files: dict[str, bytes] = {} self.signed_result: str | None = None self.request: ProcessingRequest | None = None self.run_id = "run-fake-superagent-001" @staticmethod def _handle(role: str, filename: str, value: bytes, mime_type: str) -> dict[str, object]: return { "file_handle": f"remote-{role}-001", "original_filename": filename, "sha256": hashlib.sha256(value).hexdigest(), "byte_size": len(value), "mime_type": mime_type, } def submit(self, request: ProcessingRequest, idempotency_key: str) -> RemoteRunSnapshot: self.request = request fetched = self.root / "agent" / "source.xml" fetched.parent.mkdir(parents=True, exist_ok=True) self.store.materialize( self.store.key_policy.build( ObjectAddress( request.job_id, request.attempt_no, "committed", "source_xml", ) ), fetched, 25 * 1024 * 1024, ) output_dir = self.root / "agent" / "skill-run" / "output" result_path = output_dir / "result.json" structured_path = output_dir / "structured-result.json" arguments = argparse.Namespace( xml=str(fetched.resolve()), output_dir=str(output_dir.resolve()), result_json=str(result_path.resolve()), structured_result_json=str(structured_path.resolve()), ) with contextlib.redirect_stdout(io.StringIO()): exit_code = core.process(arguments) result = json.loads(result_path.read_text(encoding="utf-8")) if exit_code != 0: raise AssertionError("synthetic success fixture failed in the deterministic Skill") values = { "daily_report": (output_dir / result["outputs"]["daily_report"]).read_bytes(), "result_json": (output_dir / "result.json").read_bytes(), "structured_result_json": (output_dir / "structured-result.json").read_bytes(), } filenames = { "daily_report": result["outputs"]["daily_report"], "result_json": "result.json", "structured_result_json": "structured-result.json", } mime_types = { "daily_report": XLSX_MIME, "result_json": "application/json", "structured_result_json": "application/json", } artifacts = { role: self._handle(role, filenames[role], value, mime_types[role]) for role, value in values.items() } artifacts["exception_report"] = None for role, value in values.items(): self.remote_files[str(artifacts[role]["file_handle"])] = value payload = { "contract_version": "arr-opera-daily-result-1", "delivery_id": "delivery-" + request.job_id, "job_id": request.job_id, "attempt_no": request.attempt_no, "remote_run_id": self.run_id, "status": "success", "business_date": result["business_date"], "processor_version": request.processor_version, "rule_set_sha256": request.rule_set_sha256, "result_schema_version": "3.0", "artifacts": artifacts, } signed = self.codec.sign( ProcessingResult.from_dict(payload), issued_at=NOW, nonce="fake-superagent-nonce-001", ) self.signed_result = signed.decode("utf-8") return RemoteRunSnapshot(self.run_id, "running") def get(self, request: ProcessingRequest, remote_run_id: str) -> RemoteRunSnapshot: if request != self.request or remote_run_id != self.run_id or self.signed_result is None: raise AssertionError("fake SuperAgent correlation failed") return RemoteRunSnapshot(self.run_id, "success", self.signed_result) def cancel(self, request: ProcessingRequest, remote_run_id: str) -> RemoteRunSnapshot: return RemoteRunSnapshot(remote_run_id, "cancelled") def materialize(self, file_handle: str, destination: Path, max_bytes: int) -> None: value = self.remote_files[file_handle] if len(value) > max_bytes: raise AssertionError("fake output exceeded its declared limit") destination.write_bytes(value) class ArrFullVerticalSliceTests(unittest.TestCase): def test_xml_object_remote_skill_arr_validation_and_atomic_fact_commit(self) -> None: with tempfile.TemporaryDirectory() as temporary: root = Path(temporary) store = ManagedObjectStore( FilesystemObjectBackend(root / "private-objects", create=True) ) codec = SignedResultCodec( {"fake-key-1": SIGNING_KEY}, signing_key_id="fake-key-1", clock=lambda: NOW, ) transport = FakeSuperAgentTransport(root, store, codec) runner = ProcessingRunner( transport, InMemoryProcessingLedger(), codec, sleep=lambda _seconds: None, ) repository = CapturingRepository() upload = ObjectStoreUploadCoordinator( object_store=store, ingestion_repository=repository, processing_starter=runner, processor_version=core.PROCESSOR_VERSION, rule_set_sha256=core.rule_set_sha256(), ) receipt = upload.submit("ARR.XML", success_xml().encode("utf-8")) self.assertIsNotNone(transport.signed_result) class SourceResolver: def source_for_attempt(self, job_id: str, attempt_no: int): self_outer.assertEqual(job_id, receipt["job_id"]) self_outer.assertEqual(attempt_no, 1) return repository.registration.source self_outer = self writeback = AgentResultWriteback( runner, SourceResolver(), ProcessingOutputRegistrar(transport, store), IngestionService( DeliveryValidator(store, policy()), repository, ), ) outcome = writeback.accept(str(transport.signed_result).encode("utf-8")) self.assertEqual(outcome.status, "committed") self.assertEqual(outcome.business_date, "2026-07-27") self.assertEqual( repository.inner.current_version_id(date.fromisoformat(outcome.business_date)), outcome.daily_version_id, ) records = repository.inner.version_records(int(outcome.daily_version_id)) self.assertEqual(len(records), 5) self.assertEqual(sum(1 for row in records if row["outcome"] == "retained"), 3) self.assertEqual( sum(int(row.get("no_of_rooms") or 0) for row in records if row["outcome"] == "retained"), 4, ) self.assertNotIn("object_key", transport.request.message()) self.assertNotIn(str(root), transport.request.message()) self.assertTrue( repository.registration.source.object_key.endswith( "/committed/source_xml/source.xml" ) ) if __name__ == "__main__": unittest.main()