"""Routing decision storage. Stores every routing decision with the full feature snapshot for audit, recalibration, and explainability. Backed by the v3_routing_decisions table. """ from __future__ import annotations from dataclasses import dataclass, field from uuid import UUID from services.intelligence_pipeline_v3.routing.router import RoutingDecision @dataclass class RoutingDecisionStore: """In-memory store for routing decisions. In production, this would be backed by the ``v3_routing_decisions`` table. This implementation provides the storage interface for use in the pipeline orchestrator and for testing. The store is append-only — decisions are immutable once stored. """ _decisions: list[RoutingDecision] = field(default_factory=list) _by_pipeline_run: dict[UUID, list[RoutingDecision]] = field(default_factory=dict) def store(self, decision: RoutingDecision) -> None: """Store a routing decision. Parameters ---------- decision: The routing decision to persist. Must have a unique id. """ self._decisions.append(decision) run_decisions = self._by_pipeline_run.setdefault( decision.pipeline_run_id, [] ) run_decisions.append(decision) def get_by_pipeline_run(self, run_id: UUID) -> list[RoutingDecision]: """Retrieve all routing decisions for a pipeline run. Parameters ---------- run_id: The pipeline run identifier. Returns ------- list[RoutingDecision] All decisions for the given run, in insertion order. Returns empty list if no decisions exist for the run. """ return list(self._by_pipeline_run.get(run_id, [])) def get_all(self) -> list[RoutingDecision]: """Retrieve all stored decisions in insertion order.""" return list(self._decisions) def count(self) -> int: """Return the total number of stored decisions.""" return len(self._decisions)