mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
Aligns the composition with its entry point (the `ara_first_run` lambda + `AraFirstRunTriggerBody`): clearer what the file does. - orchestration/first_run_pipeline.py → ara_first_run_pipeline.py - FirstRunPipeline → AraFirstRunPipeline; FirstRunCommand → AraFirstRunCommand - test files renamed to match Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
70 lines
2.3 KiB
Python
70 lines
2.3 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Protocol
|
|
|
|
|
|
class AraFirstRunCommand(Protocol):
|
|
"""The slice of the trigger the pipeline threads downstream.
|
|
|
|
Only the business fields — UPRNs and Scenario definitions are read from
|
|
their source-of-truth tables, not carried here. ``task_id``/``sub_task_id``
|
|
are deliberately absent: the SubTask lifecycle is the decorator's concern,
|
|
not the pipeline's. ``AraFirstRunTriggerBody`` satisfies this structurally,
|
|
so ``orchestration`` need not import the application-layer event type.
|
|
"""
|
|
|
|
@property
|
|
def portfolio_id(self) -> int: ...
|
|
|
|
@property
|
|
def property_ids(self) -> list[int]: ...
|
|
|
|
@property
|
|
def scenario_ids(self) -> list[int]: ...
|
|
|
|
|
|
class IngestionStage(Protocol):
|
|
"""Stage 1 — acquires and persists each Property's external source data."""
|
|
|
|
def run(self, property_ids: list[int]) -> None: ...
|
|
|
|
|
|
class PropertyBaselineStage(Protocol):
|
|
"""Stage 2 — establishes each Property's Baseline Performance."""
|
|
|
|
def run(self, property_ids: list[int]) -> None: ...
|
|
|
|
|
|
class ModellingStage(Protocol):
|
|
"""Stage 3 — scores each Property against its Scenarios into Plans."""
|
|
|
|
def run(self, property_ids: list[int], scenario_ids: list[int]) -> None: ...
|
|
|
|
|
|
class AraFirstRunPipeline:
|
|
"""Composes the First Run stages end-to-end: Ingestion -> Baseline ->
|
|
Modelling.
|
|
|
|
Threads **only** ``property_ids`` between stages (and ``scenario_ids`` into
|
|
Modelling, off the command — not a prior stage). The stages communicate
|
|
through repos, never via in-memory hand-off, which is what makes each stage
|
|
independently runnable for the single-property review flow (ADR-0011,
|
|
ADR-0003). Stage orchestrators are injected so the handler owns wiring and
|
|
tests substitute fakes.
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
*,
|
|
ingestion: IngestionStage,
|
|
baseline: PropertyBaselineStage,
|
|
modelling: ModellingStage,
|
|
) -> None:
|
|
self._ingestion = ingestion
|
|
self._baseline = baseline
|
|
self._modelling = modelling
|
|
|
|
def run(self, command: AraFirstRunCommand) -> None:
|
|
self._ingestion.run(command.property_ids)
|
|
self._baseline.run(command.property_ids)
|
|
self._modelling.run(command.property_ids, command.scenario_ids)
|