"""drop rulebook subscriptions and per-project suppressions Revision ID: 0101 Revises: 0100 Create Date: 2026-09-15 Milestone 414. A rule lives in a rulebook topic, where it is GLOBAL, or on one project, and retrieval reads that home directly (step 1). Subscriptions were the last thing that pretended a rulebook reached some projects and not others, and after milestone 394 they changed nothing a session received — only what a project's rule LISTING showed. Operator, 2026-09-15: "we have global and project scoped rules, we don't need the subscriptions now." WHAT GOES - ``project_rulebook_subscriptions`` (migration 0058). - ``project_rule_suppressions`` and ``project_topic_suppressions``. They let a project mute rules from a rulebook it subscribed to. With no subscription there is nothing to mute; a project that departs from a global rule writes a project rule with an ``overrides`` relation, which says why. - The ``subscribe_rulebooks`` key inside ``projects.inception.choices``, and the ``exclude_always_on_rulebooks`` key milestone 394 left behind in the same place. Both describe decisions that can no longer be made; a stored record carrying them would be read back as a choice the product offers. IRREVERSIBLE, AND THE DOWNGRADE SAYS SO The downgrade recreates the three tables empty. Which projects subscribed to which rulebooks, and what they muted, is in what this drops. Restore a backup taken before this ran if the prior state matters. """ import sqlalchemy as sa from alembic import op revision = "0101" down_revision = "0100" branch_labels = None depends_on = None def upgrade() -> None: op.drop_table("project_topic_suppressions") op.drop_table("project_rule_suppressions") op.drop_table("project_rulebook_subscriptions") op.execute( """ UPDATE projects SET inception = jsonb_set( inception, '{choices}', (inception->'choices') - 'subscribe_rulebooks' - 'exclude_always_on_rulebooks' ) WHERE inception IS NOT NULL AND jsonb_typeof(inception->'choices') = 'object' """ ) def _join_table(name: str, other: str, other_table: str) -> None: op.create_table( name, sa.Column( "project_id", sa.BigInteger(), sa.ForeignKey("projects.id", ondelete="CASCADE"), primary_key=True, nullable=False, ), sa.Column( other, sa.BigInteger(), sa.ForeignKey(f"{other_table}.id", ondelete="CASCADE"), primary_key=True, nullable=False, ), sa.Column( "created_at", sa.DateTime(timezone=True), server_default=sa.text("now()"), nullable=True, ), ) def downgrade() -> None: """Structure only. See the module docstring — the rows are gone.""" _join_table("project_rulebook_subscriptions", "rulebook_id", "rulebooks") _join_table("project_rule_suppressions", "rule_id", "rules") _join_table("project_topic_suppressions", "topic_id", "rulebook_topics")