"""ask_events 테이블 ORM — /ask 호출 관측 (Phase 3.5a migration 102, Phase 3.5b 배선) threshold calibration + verifier FP 분석 + defense layer 디버깅 데이터. """ from datetime import datetime from typing import Any from sqlalchemy import BigInteger, Boolean, DateTime, Float, ForeignKey, Integer, String, Text from sqlalchemy.dialects.postgresql import JSONB from sqlalchemy.orm import Mapped, mapped_column from core.database import Base class AskEvent(Base): __tablename__ = "ask_events" id: Mapped[int] = mapped_column(BigInteger, primary_key=True) query: Mapped[str] = mapped_column(Text, nullable=False) user_id: Mapped[int | None] = mapped_column( BigInteger, ForeignKey("users.id", ondelete="SET NULL") ) completeness: Mapped[str | None] = mapped_column(Text) # full / partial / insufficient synthesis_status: Mapped[str | None] = mapped_column(Text) confidence: Mapped[str | None] = mapped_column(Text) # high / medium / low refused: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False) classifier_verdict: Mapped[str | None] = mapped_column(Text) # sufficient / insufficient max_rerank_score: Mapped[float | None] = mapped_column(Float) aggregate_score: Mapped[float | None] = mapped_column(Float) hallucination_flags: Mapped[list[Any] | None] = mapped_column(JSONB, default=list) evidence_count: Mapped[int | None] = mapped_column(Integer) citation_count: Mapped[int | None] = mapped_column(Integer) defense_layers: Mapped[dict[str, Any] | None] = mapped_column(JSONB) total_ms: Mapped[int | None] = mapped_column(Integer) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), default=datetime.now, nullable=False )