from __future__ import annotations from dataclasses import dataclass from orchestration.ara_first_run_pipeline import AraFirstRunCommand, AraFirstRunPipeline @dataclass class _FakeCommand: """A stand-in for AraFirstRunTriggerBody — structurally a AraFirstRunCommand.""" portfolio_id: int property_ids: list[int] scenario_ids: list[int] class _SpyIngestion: def __init__(self, log: list[tuple[object, ...]]) -> None: self._log = log def run(self, property_ids: list[int]) -> None: self._log.append(("ingestion", property_ids)) class _SpyBaseline: def __init__(self, log: list[tuple[object, ...]]) -> None: self._log = log def run(self, property_ids: list[int]) -> None: self._log.append(("baseline", property_ids)) class _SpyModelling: def __init__(self, log: list[tuple[object, ...]]) -> None: self._log = log def run(self, property_ids: list[int], scenario_ids: list[int]) -> None: self._log.append(("modelling", property_ids, scenario_ids)) def test_run_sequences_the_three_stages_threading_only_property_ids() -> None: # Arrange log: list[tuple[object, ...]] = [] command: AraFirstRunCommand = _FakeCommand( portfolio_id=1, property_ids=[10, 11], scenario_ids=[7] ) pipeline = AraFirstRunPipeline( ingestion=_SpyIngestion(log), baseline=_SpyBaseline(log), modelling=_SpyModelling(log), ) # Act pipeline.run(command) # Assert — Ingestion -> Baseline -> Modelling, in order. Ingestion and # Baseline receive only property_ids; Modelling additionally gets the # scenario_ids (off the command, not a prior stage). Nothing else is # threaded between stages — they communicate through repos (ADR-0011). assert log == [ ("ingestion", [10, 11]), ("baseline", [10, 11]), ("modelling", [10, 11], [7]), ]