Rifqi Hafizuddin
[KM-626][AI] Slow-path wiring prep: context + persistence seams, retrieve_documents few-shot
3b27b6b
Raw
History Blame
1.64 kB
"""AnalysisStore — the seam the slow path persists its AnalysisRecord through.
The Assembler produces an `AnalysisRecord` (the faithful, structured record of a
run — §8.3, INV-4). Persisting it is a separate concern from streaming the answer,
so it sits behind this one-method seam.
`NullAnalysisStore` is the default: it logs that a record was produced but stores
nothing, because the backing table does not exist yet. The plan is to store records
in the **same catalog DB** (Neon `dataeyond`, `settings.postgres_connstring`).
TODO(persistence): add a Postgres-backed `AnalysisStore` writing an
`analysis_records` table in the catalog DB, keyed on
(business_context_id, plan_id, created_at), then inject it into ChatHandler.
"""
from __future__ import annotations
from typing import Protocol, runtime_checkable
from src.middlewares.logging import get_logger
from .schemas import AnalysisRecord
logger = get_logger("analysis_store")
@runtime_checkable
class AnalysisStore(Protocol):
"""Persist a completed analysis. Implementations must never raise on the
caller's path — a persistence failure must not break the user's answer."""
async def save(self, record: AnalysisRecord) -> None: ...
class NullAnalysisStore:
"""Default no-op store: logs the record, persists nothing (no table yet)."""
async def save(self, record: AnalysisRecord) -> None:
logger.info(
"analysis_record produced (not persisted — no store configured)",
plan_id=record.plan_id,
business_context_id=record.business_context_id,
n_tasks=len(record.tasks_run),
)