from datetime import date as date_type from datetime import datetime from sqlalchemy import Date, DateTime, Float, String, Text from sqlalchemy.orm import Mapped, mapped_column from app.database import Base class RegimeFundamentalObservation(Base): """Point-in-time record of the sourced hyperscaler capex / earnings read. One row per ``effective_date`` (unique, upserted). Before this table the observation lived in a single ``SystemSetting`` slot, so every refresh overwrote the previous one and no history existed at all — which made the read impossible to replay, impossible to backtest, and meant a snapshot rebuild could only ever score historical sessions as if nothing had been observed. The read is a categorical channel reported beside State and Warning, never a term in either, so this series is not a scoring input. It is the record that makes the channel replayable at all -- and the only route to eventually testing whether it improves prediction conditional on Warning, which is the one thing that could justify combining the channels later. ``effective_date`` rather than ``fetched_at`` is the key: it is the session the observation becomes usable on (normally the next weekday), and the gate that stops a rebuild stamping today's reading onto historical rows. """ __tablename__ = "regime_fundamental_observations" id: Mapped[int] = mapped_column(primary_key=True) effective_date: Mapped[date_type] = mapped_column( Date, nullable=False, unique=True, index=True ) f1_score: Mapped[float | None] = mapped_column(Float, nullable=True) f3_score: Mapped[float | None] = mapped_column(Float, nullable=True) capex_json: Mapped[str] = mapped_column(Text, nullable=False) good_news_stock_down: Mapped[str] = mapped_column(String(10), nullable=False) reasoning: Mapped[str | None] = mapped_column(Text, nullable=True) source: Mapped[str] = mapped_column(String(30), nullable=False) fetched_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False)