From 15cbb158e307305b3a615739d901f22b125bcee3 Mon Sep 17 00:00:00 2001 From: Arron Atchison Date: Mon, 27 Jul 2026 13:43:17 -0700 Subject: [PATCH] DEMO ONLY - do not merge: prove the additivity gate goes red Throwaway non-additive migration, to show the migration-additivity CI job firing. #1770 adds no migrations, so its own run reports 'nothing to check' and never exercises the checker invocation path. Covers three cases: 1. op.drop_column reached only through a helper (call-graph following) 2. add_column(nullable=False) with no server_default 3. destructive raw DDL via op.get_bind().execute() The destructive downgrade() must NOT be flagged. Co-Authored-By: Claude Opus 4.8 (1M context) --- ..._27_1200-deadbeef0001_demo_non_additive.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 backend/src/appointment/migrations/versions/2026_07_27_1200-deadbeef0001_demo_non_additive.py diff --git a/backend/src/appointment/migrations/versions/2026_07_27_1200-deadbeef0001_demo_non_additive.py b/backend/src/appointment/migrations/versions/2026_07_27_1200-deadbeef0001_demo_non_additive.py new file mode 100644 index 000000000..e4cac14b0 --- /dev/null +++ b/backend/src/appointment/migrations/versions/2026_07_27_1200-deadbeef0001_demo_non_additive.py @@ -0,0 +1,36 @@ +"""DEMO ONLY - deliberately non-additive. Do not merge. + +Exists to prove the `migration-additivity` CI job actually goes red. +See thunderbird/appointment#1770. + +Revision ID: deadbeef0001 +Revises: d4e5f6a7b8c9 +Create Date: 2026-07-27 12:00:00.000000 +""" + +import sqlalchemy as sa +from alembic import op + +revision = 'deadbeef0001' +down_revision = 'd4e5f6a7b8c9' +branch_labels = None +depends_on = None + + +def _tidy_up(): + """Hidden in a helper on purpose: proves the scan follows call graphs.""" + op.drop_column('subscribers', 'ftue_level') + + +def upgrade() -> None: + # 1. destructive call reached only via a helper + _tidy_up() + # 2. NOT NULL with no server_default -> old replicas' INSERTs start failing + op.add_column('subscribers', sa.Column('demo_flag', sa.Boolean(), nullable=False)) + # 3. raw DDL through a non-`op` receiver + op.get_bind().execute(sa.text('ALTER TABLE subscribers DROP COLUMN avatar_url')) + + +def downgrade() -> None: + # Destructive, but never executed by a deploy -> must NOT be flagged. + op.drop_column('subscribers', 'demo_flag')