"""Audit writer: upserts a row in kevin_signal_bridge_state per processed mention.""" from __future__ import annotations import uuid from decimal import Decimal from typing import Any, Callable from sqlalchemy.dialects.postgresql import insert as pg_insert from shared.models.meet_kevin_trading import KevinSignalBridgeState from shared.models.trading import Signal as SignalRow from shared.schemas.trading import TradeSignal class AuditWriter: def __init__(self, session_factory: Callable[..., Any]) -> None: self.session_factory = session_factory async def persist_signal(self, signal: TradeSignal) -> None: """Persist a TradeSignal to the `signals` table so downstream FKs (kevin_signal_bridge_state.signal_id, trades.signal_id) resolve. Idempotent on the signal UUID — caller should call once per published signal before writing the audit row. """ async with self.session_factory() as session: stmt = pg_insert(SignalRow).values( id=signal.signal_id, ticker=signal.ticker, direction=signal.direction, strength=signal.strength, strategy_sources={"sources": signal.strategy_sources}, strategy_id=signal.strategy_id, acted_on=False, ) # Idempotent — if the row already exists (e.g. retry path) # leave it alone. stmt = stmt.on_conflict_do_nothing(index_elements=["id"]) await session.execute(stmt) await session.commit() async def write( self, *, mention_id: int, bridge_status: str, effective_conviction: Decimal | None = None, signal_id: uuid.UUID | None = None, trade_id: uuid.UUID | None = None, notes: str | None = None, ) -> None: """Upsert one audit row (mention_id is unique).""" async with self.session_factory() as session: stmt = pg_insert(KevinSignalBridgeState).values( id=uuid.uuid4(), mention_id=mention_id, bridge_status=bridge_status, effective_conviction=effective_conviction, signal_id=signal_id, trade_id=trade_id, notes=notes, ) stmt = stmt.on_conflict_do_update( index_elements=["mention_id"], set_={ "bridge_status": stmt.excluded.bridge_status, "effective_conviction": stmt.excluded.effective_conviction, "signal_id": stmt.excluded.signal_id, "trade_id": stmt.excluded.trade_id, "notes": stmt.excluded.notes, }, ) await session.execute(stmt) await session.commit()