Skip to content

Drop the simulation-domain v2 tables, their enum types and the retired association columns - #4014

Draft
anth-volk wants to merge 4 commits into
v2plan/1h-130-stop-using-simulation-tablesfrom
v2plan/1h-131-drop-simulation-tables
Draft

anth-volk wants to merge 4 commits into
v2plan/1h-130-stop-using-simulation-tablesfrom
v2plan/1h-131-drop-simulation-tables

Conversation

@anth-volk

Copy link
Copy Markdown
Collaborator

Fixes #4013

Summary

Stacked on #4007, which removed the models of the 15 simulation-domain v2 tables and stopped mapping the retired country and label association columns. It kept the tables and columns as schema-only declarations so the metadata still matched the schema. This PR deletes those declarations and adds the revision that drops them. The simulation service owns these tables in its own simulation schema, with its own replacements for all of them except aggregates and change_aggregates (v2 alpha's custom totals, which have no replacement).

Revision 363f34954a14 was generated with uv run alembic -c alembic-v2.ini revision --autogenerate against a disposable PostgreSQL database at fbb7488ebe8a. Autogeneration detected exactly the 15 tables (with their indexes) and the 4 columns. The file was then formatted with ruff format, like the other v2 revisions, and given three post-generation corrections. Each correction is commented in the revision and documented in docs/engineering/skills/alembic-migrations.md; the rule there allows corrections for reversibility or an objectively wrong generated operation:

  1. Drop and create order. Alembic emits removed tables in arbitrary order. The generated upgrade dropped reports before report_runs, which references it, and the generated downgrade created output tables before simulations and report_runs, so both failed on foreign keys. The upgrade now drops each table before the tables it references; the downgrade creates them in the reverse order.
  2. Enum types. Alembic drops the tables but leaves their 8 native enum types (v2_aggregate_type, v2_decile_type, v2_household_job_status, v2_output_status, v2_report_run_status, v2_report_run_trigger, v2_simulation_status, v2_simulation_type), and the generated downgrade could not create them again while they existed. The upgrade drops them.
  3. One check constraint. Reflection strips the outer parentheses of ck_simulations_filter_pair ((filter_field IS NULL) = (filter_value IS NULL)), which left invalid SQL in the generated downgrade. They are restored as the model declared them.

Apart from those corrections, the downgrade statements are exactly the generated ones. The downgrade recreates the tables and columns empty.

Other changes:

  • V2_ALEMBIC_HEAD_REVISION moves to 363f34954a14, and the privilege manifest no longer lists the 15 tables.
  • The v2 metadata validation rejects the 15 table names.
  • New rule api.v2.simulation-tables-stay-removed. tests/unit/v2/test_simulation_domain_boundaries.py fails when any module under policyengine_api, scripts or tests, or the v2 migration environment, imports a removed model or one of the removed modules. That includes imports from the parent package and relative imports. It also fails when the metadata declares one of the tables. The rule has proof fixtures and is rendered into docs/generated/rules.md and AGENTS.md. Rule changes may be approved by any core developer, so this PR requests a review from core-developers.
  • Documentation. The Alembic migrations skill gains a section on this revision. The Stage 12A rollback steps say that once this revision has run, a rollback to a pre-Stage 12A release first needs the v2 schema downgraded to fbb7488ebe8a. The Stage 12 worker contract no longer names the dropped tables.

Migration scope: no route group, workflow or user-visible API contract changes. Nothing moves off the Flask/API v1 path. No inline suppressions are added; the one #4007 added goes away with the module it imported.

Environment variables

None. The changed code reads and declares no environment variable. The revision runs in the existing release migration job, and the privilege manifest reaches the deploy through the existing scripts/reconcile_v2_privileges.py step in .github/workflows/seed-v2-database.yml. This PR changes neither, nor their variables.

Merge requirements

Do not merge until all of these hold:

  1. Operator step: row counts of the 15 tables in the v2 Supabase database show every table empty in both staging and production. The downgrade recreates the tables empty, so rows dropped here cannot be restored without a backup.
  2. Stop using the simulation-domain v2 tables and retired association columns #4007 is merged and deployed to staging and production. The release workflow runs this revision before the new Cloud Run revision serves traffic, so the release serving traffic while it runs must be Stop using the simulation-domain v2 tables and retired association columns #4007's release or later.
  3. CI on this PR (it runs in full once Stop using the simulation-domain v2 tables and retired association columns #4007 merges and this PR is rebased onto master) and an approving review, including one from a core developer for the rule change.

If another v2 revision merges first (the planned countries table revision uses the same Alembic chain), this PR is rebased and its revision regenerated on the new head.

Testing

  • Against disposable PostgreSQL: alembic -c alembic-v2.ini check reports no new operations at head. tests/integration/test_alembic_v2_lifecycle.py passes, and covers:

    • upgrade to head, then downgrade to fbb7488ebe8a, which restores the 15 tables, the 8 enum types and the 4 nullable columns, then upgrade again;
    • a comparison of the schema the downgrade recreates with the one the earlier revisions created: columns with types, nullability and defaults, keys, unique and check constraints, indexes, and enum values. Changing one check in the downgrade makes it fail;
    • the full base-to-head cycle;
    • head serving the previous application release's use of every table it maps: it reflects fbb7488ebe8a without the dropped tables and columns, then inserts, reads, rewrites and deletes a row in each table, and deletes a user who owns association rows;
    • the same check for the pre-Stage 12A release against fbb7488ebe8a, which the updated rollback steps rely on.

    These tests fail without the revision (Can't locate revision identified by '363f34954a14').

  • Also against disposable PostgreSQL and MySQL: test_v2_catalog_publication.py, test_v2_user_identity_persistence.py, test_v2_privilege_reconciliation.py (after reconcile_v2_privileges.py apply and verify), test_v2_stage12_comparison_persistence.py, test_v2_household_persistence.py, test_v2_policy_persistence.py, the cross-database dual-write tests and test_alembic_mysql_lifecycle.py: all passed.

  • Unit tests check the revision text: it drops exactly the 15 tables and 4 columns, and recreates them in the downgrade; it has exactly these three corrections; it drops the 8 enum types; and the drop and create order respects every foreign key. Other unit tests check the metadata, the manifest and the rule. uv run pytest tests/unit/v2 tests/contract -q: 1042 passed. The rest of tests/unit and tests/to_refactor: 2331 passed.

  • python -m scripts.rules guard --base-ref origin/master fails while the new guard test is unregistered and passes with the registry entry. A temporary module importing Report from the v2 models makes the guard test fail.

  • mypy, ruff format --check, ruff check, scripts/run_quality_guards.py and scripts/export_migration_contracts.py (no changes): all passed.

🤖 Generated with Claude Code

anth-volk and others added 4 commits October 22, 2026 17:54
The simulation service owns household jobs, simulations, reports, report
runs and their outputs in its own simulation schema. The previous release
removed the Public API's models of those 15 tables and stopped mapping
the retired country and label columns of the simulation and report
associations, keeping them only as schema-only declarations.

Delete those declarations. Revision 363f34954a14, autogenerated, drops
the 15 tables and the four columns. Its post-generation corrections,
commented in the revision and documented in the Alembic migrations skill:

- drop each table before the tables its foreign keys reference, and
  create them in the reverse order in the downgrade (Alembic emits
  removed tables in arbitrary order, which fails on the foreign keys);
- drop the eight native enum types the tables used (Alembic leaves them,
  and the generated downgrade could not then create them again);
- restore the parentheses that reflection strips from
  ck_simulations_filter_pair, which left invalid SQL in the downgrade.

V2_ALEMBIC_HEAD_REVISION moves to the new revision. The v2 metadata
validation rejects the 15 table names, and the privilege manifest no
longer lists them. The lifecycle test covers the upgrade, the downgrade
to the previous revision and the re-upgrade, and its test of the previous
application revision now runs against the revision before this one: head
drops exactly these tables and columns, which that release no longer
maps, and serves everything else it maps. The Stage 12A rollback steps
and the Stage 12 worker contract say what this removal changes.

This must deploy only after the previous release is deployed in both
environments and an operator has confirmed that the tables are empty.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The previous commit dropped the Public API's copies of the 15
simulation-domain tables, which the simulation service owns in its own
schema. Rule api.v2.simulation-tables-stay-removed keeps them out:

- test_simulation_domain_boundaries reads every module under
  policyengine_api, scripts and tests, and the v2 migration environment,
  and fails when one imports a removed model, the removed models/reports,
  models/simulations or models/retired_tables modules, or the removed
  report_runs module, including from the parent package and relatively;
- it fails if the v2 metadata declares one of the 15 tables, or the
  models package exports a removed model (moved from test_models);
- the metadata validation test that rejects their table names is the
  rule's third check.

Its proof fixtures use imports the household migration qualification and
the report-run tests made before the models were removed. The registry
renders the rule into docs/generated/rules.md and AGENTS.md, and the
Alembic migrations and testing skills cite it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of the removal revision found three gaps in the lifecycle tests:

- The downgrade was checked only for the presence of the tables, enum
  types and columns. A new test builds the schema from empty up to the
  revision before the removal, upgrades to head, downgrades again, and
  requires every recreated table and association table to match what the
  earlier revisions created: columns with types, nullability and
  defaults, keys, unique and check constraints, indexes, and the enum
  types' values. Changing one check in the downgrade makes it fail.
- Repurposing the previous-revision test removed the only test that ran
  the pre-Stage 12A release against the Stage 12A schema, which the
  updated rollback steps rely on after a downgrade to fbb7488ebe8a. It is
  back as its own test, against that revision instead of head; both tests
  share one helper, with each previous revision's usage in a
  PreviousRevisionUsage value.
- The native UUID idempotency test now builds report_runs from the
  baseline revision, as its name says, instead of from the removal
  revision's downgrade.

Tests only: they pass before and after, except the mutation check above.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The simulation service has its own replacements for 13 of the 15 dropped
tables; aggregates and change_aggregates, v2 alpha's custom totals, were
unused and have none. Several places said it owns all 15. The table set
is renamed SIMULATION_DOMAIN_TABLES and its comment, the validation
message, the Alembic migrations skill, the changelog fragment, the rule
statement and the guard test's docstring now say so. Test names that
called them simulation-service tables follow.

Outdated passages found in review: the Stage 12A document's head
revision and its description of the previous-revision test, which now
upgrades to fbb7488ebe8a instead of head, and the comments in catalog
publication and the household migration qualification.

Wording, names and documentation only: no behavior changes, so no test
can fail before this change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@anth-volk
anth-volk requested a review from a team October 22, 2026 14:35
@anth-volk
anth-volk added this pull request to stack #4015 October 22, 2026 14:35
@codecov

codecov Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.69%. Comparing base (943601c) to head (c61fbe6).

Additional details and impacted files
@@                              Coverage Diff                               @@
##           v2plan/1h-130-stop-using-simulation-tables    #4014      +/-   ##
==============================================================================
- Coverage                                       87.72%   87.69%   -0.04%     
==============================================================================
  Files                                             257      256       -1     
  Lines                                           15768    15723      -45     
  Branches                                         2616     2614       -2     
==============================================================================
- Hits                                            13833    13788      -45     
  Misses                                           1265     1265              
  Partials                                          670      670              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

This branch was successfully deployed

1 active deployment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Drop the Public API's copies of the simulation-domain v2 tables and the retired association columns

1 participant