Model/applications/ara_first_run/ara_first_run_trigger_body.py
Khalim Conn-Kowlessar 75fbba60fc feat(ara): AraFirstRunTriggerBody + ara_first_run lambda skeleton (#1130)
Stage-2 entry point for the First Run use case. Adds the
`ara_first_run` Lambda package mirroring the `postcode_splitter`
template, its typed trigger contract, and a stub `FirstRunPipeline`.

- `AraFirstRunTriggerBody`: thin command of five fields — `task_id`,
  `sub_task_id` (UUID, lifecycle), `portfolio_id`, `property_ids`,
  `scenario_ids` (int business IDs). No `model_config` override, so
  Pydantic's default `extra="ignore"` lets the FastAPI backend add
  fields without breaking deployed lambdas. UPRNs / Scenario defs are
  deliberately off the event — read from source-of-truth tables.
- Thin `handler.py`: validate-and-delegate only, via a named
  `dispatch_first_run` seam (testable without the Lambda runtime).
  Subtask status (in-progress/complete/failed) + CloudWatch log URL
  come for free from the existing `@subtask_handler()` decorator.
- `FirstRunPipeline` (orchestration/) stub: `run(command)` receives the
  validated command. Declares a structural `FirstRunCommand` Protocol
  (the three business fields) that `AraFirstRunTriggerBody` satisfies,
  so orchestration needs no application-layer import — rhymes with the
  `EpcFetcher`/`SolarFetcher` Protocols on IngestionOrchestrator
  (ADR-0011). Full Ingestion→Baseline→Modelling composition lands in
  #1136.
- Dockerfile / requirements.txt / local_handler/ mirror postcode_splitter.

TDD: 7 new tests (trigger-body validation incl. forward-compat +
id-types, pipeline seam, handler delegation). pyright strict clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 20:38:15 +00:00

25 lines
850 B
Python

from __future__ import annotations
from uuid import UUID
from pydantic import BaseModel
class AraFirstRunTriggerBody(BaseModel):
"""The SQS event the ``ara_first_run`` Lambda is triggered with.
A thin command. ``task_id``/``sub_task_id`` drive the SubTask lifecycle (the
``@subtask_handler`` decorator reads them); the three business fields are what
the pipeline threads downstream. UPRNs and Scenario definitions are
deliberately absent — they are read from their source-of-truth tables, not
carried on the event (issue #1130).
No ``model_config`` override: Pydantic's default ``extra="ignore"`` lets the
FastAPI backend add fields to the payload without breaking deployed lambdas.
"""
task_id: UUID
sub_task_id: UUID
portfolio_id: int
property_ids: list[int]
scenario_ids: list[int]