2026-05-24 01:03:53 +00:00
|
|
|
"""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
|
2026-05-26 21:23:59 +00:00
|
|
|
from shared.models.trading import Signal as SignalRow
|
|
|
|
|
from shared.schemas.trading import TradeSignal
|
2026-05-24 01:03:53 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class AuditWriter:
|
|
|
|
|
def __init__(self, session_factory: Callable[..., Any]) -> None:
|
|
|
|
|
self.session_factory = session_factory
|
|
|
|
|
|
2026-05-26 21:23:59 +00:00
|
|
|
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()
|
|
|
|
|
|
2026-05-24 01:03:53 +00:00
|
|
|
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()
|