"""conversations.last_curator_run_at — tracks scheduler progress per-conversation Revision ID: 0048 Revises: 0047 Create Date: 2026-05-22 Phase 2 of the conversation+curator architecture (Fable #172). The scheduler runs every 15 minutes and processes any journal conversation with messages newer than its `last_curator_run_at` timestamp. NULL means "never run; process all of today on first sweep." """ from alembic import op import sqlalchemy as sa revision = "0048" down_revision = "0047" branch_labels = None depends_on = None def upgrade() -> None: op.add_column( "conversations", sa.Column( "last_curator_run_at", sa.DateTime(timezone=True), nullable=True, ), ) # Indexed because the scheduler's selection query is # WHERE conversation_type='journal' AND (last_curator_run_at IS NULL OR ...) # which benefits from a partial index narrowed to journal rows. op.create_index( "ix_conversations_journal_last_curator", "conversations", ["last_curator_run_at"], postgresql_where=sa.text("conversation_type = 'journal'"), ) def downgrade() -> None: op.drop_index( "ix_conversations_journal_last_curator", table_name="conversations", ) op.drop_column("conversations", "last_curator_run_at")