Files
signal-platform/alembic/versions/033_regime_fundamental_observations.py
dennisthiessenandClaude Opus 5 c97a067e0e
Deploy / lint (push) Successful in 8s
Deploy / test (push) Successful in 1m27s
Deploy / deploy (push) Successful in 37s
fix(risk-monitor): drop an unused import and align migration 033 with its model
ruff F401 failed the deploy: `import pytest` in test_event_study.py outlived the
pytest.approx assertion it was added for.

Compiling the migration for Postgres while checking that turned up a second
defect worth fixing while the table is still empty. It created a unique
constraint *and* a plain index on effective_date, while the model declares
`unique=True, index=True` -- one unique index. Both enforce uniqueness, but the
pairing left a redundant second index on the column and a permanent diff for
autogenerate to keep trying to reconcile. Now renders byte-for-byte what the
model declares, matching RegimeSnapshot.date.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 11:31:05 +02:00

71 lines
3.0 KiB
Python

"""Point-in-time history for the sourced fundamental observation
Revision ID: 033
Revises: 032
Create Date: 2026-08-12 00:00:00.000000
The hyperscaler capex / "good news, stock down" read lived in a single
``SystemSetting`` slot, so each refresh overwrote the last and no history
existed. The read is now a categorical channel reported alongside State and
Warning (never a term in either), and a channel with no history cannot be
replayed: a snapshot rebuild would record every historical session as if nothing
had ever been observed, and the event study could not measure the channel at all.
Keyed on ``effective_date`` (the session the observation becomes usable on,
normally the next weekday) rather than ``fetched_at``, because that is the gate
that stops a rebuild stamping today's reading onto historical rows.
The table starts empty. ``update_regime_monitor`` records the currently stored
observation on its next run, so a deployment does not lose the live reading —
but genuine history does not exist and cannot be invented here. Backfilling it
from the SEC capex line and earnings-date reactions is separate work; until then
every historical session reads ``unknown``, which is the honest value rather than
a guessed one.
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
revision: str = "033"
down_revision: Union[str, None] = "032"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
op.create_table(
"regime_fundamental_observations",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("effective_date", sa.Date(), nullable=False),
sa.Column("f1_score", sa.Float(), nullable=True),
sa.Column("f3_score", sa.Float(), nullable=True),
sa.Column("capex_json", sa.Text(), nullable=False),
sa.Column("good_news_stock_down", sa.String(length=10), nullable=False),
sa.Column("reasoning", sa.Text(), nullable=True),
sa.Column("source", sa.String(length=30), nullable=False),
sa.Column("fetched_at", sa.DateTime(timezone=True), nullable=False),
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
sa.PrimaryKeyConstraint("id"),
)
# One unique index, not a unique constraint plus a plain index: the model
# declares `unique=True, index=True`, which SQLAlchemy renders as exactly
# this. The constraint-plus-index pairing worked but left a redundant second
# index on the column and a permanent metadata diff for autogenerate to keep
# trying to reconcile. Matches RegimeSnapshot.date, the sibling table.
op.create_index(
"ix_regime_fundamental_observations_effective_date",
"regime_fundamental_observations",
["effective_date"],
unique=True,
)
def downgrade() -> None:
op.drop_index(
"ix_regime_fundamental_observations_effective_date",
table_name="regime_fundamental_observations",
)
op.drop_table("regime_fundamental_observations")