Repository navigation
Replace the full-catalog integration tests with selected folders of the installed models - #4150
Merged
Merged
Conversation
Tests for a small catalog holding one example of each value shape extraction accepts, published to PostgreSQL on every pull request; for .github/scripts/decide_full_catalog_tests.sh, which decides whether a change can affect the full-catalog tests; and for a separate full-catalog-integration job that runs both of those tests in one process only when the decision says so. Refs #4149 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…them The two tests that load the complete installed PolicyEngine.py catalog move out of catalog-runtime-integration into a new job, full-catalog-integration, which runs them in one pytest process that extracts the catalog once. Its first step, .github/scripts/decide_full_catalog_tests.sh, compares the commit with the pull request's base or the commit before the push, and the tests run only when the change touches the locked packages, the catalog code or its table models, the v2 schema, the tests or the workflow. Scheduled runs, now nightly, and manual runs always run them. The job itself always runs, so "CI complete" and the release run's check of the merge run keep working. Every pull request now publishes a small catalog holding one example of each value shape extraction accepts, and checks that each comes back from PostgreSQL unchanged. Fixes #4149 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #4150 +/- ##
===========================================
+ Coverage 50.84% 88.14% +37.30%
===========================================
Files 270 286 +16
Lines 15221 16659 +1438
Branches 2443 2733 +290
===========================================
+ Hits 7739 14684 +6945
+ Misses 6841 1300 -5541
- Partials 641 675 +34 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
The workflow tests now require that full-catalog-integration has no conditional step and no decision step, checks out only the commit it tests, and that the workflow has no schedule. Refs #4149 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
full-catalog-integration no longer decides whether to run its tests: the decision step, .github/scripts/decide_full_catalog_tests.sh and its tests, every step condition, the full-history checkout and the nightly schedule are gone. The job still runs beside catalog-runtime-integration, with both full-catalog tests in one pytest process sharing one catalog extraction, so the cross-database check takes as long as the slower of the two jobs. Refs #4149 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A new integration test runs the real US and UK models through extraction and publication, reduced to eight parameter folders that between them hold every value shape the installed models hold, and checks that every extracted value comes back from PostgreSQL unchanged. It fails by name when a listed folder no longer exists. The workflow tests now require that the cross-database check has one job, catalog-runtime-integration, which runs that test and no full-catalog test, with no conditional step. The row comparison helpers move to tests/integration/catalog_rows.py so both publication tests share them. Refs #4149 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The cross-database check goes back to one job, catalog-runtime-integration. The full-catalog-integration job, both full-catalog tests (test_v2_catalog_installed.py and test_v2_catalog_publication_qualification.py), their shared extraction helper and the RUN_V2_CATALOG_COMPATIBILITY and RUN_V2_CATALOG_PUBLICATION_QUALIFICATION switches are removed. A new step publishes selected parameter folders of the installed US and UK models on every run (test_v2_catalog_installed_folders.py), beside the edge-case value catalog test. This gives up the 256 MB memory limit on publication, publishing the full catalog before merge, and the exact per-bundle catalog counts and region dataset routing that test_v2_catalog_installed.py pinned. Each release still publishes and validates the complete catalog against staging, then production. Fixes #4149 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
marked this pull request as ready for review
November 2, 2026 14:26
This branch was previously deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #4149
Summary
CI no longer loads the complete installed PolicyEngine.py catalog (about 1.2 million parameter values). Two tests replace the two full-catalog tests, and both run on every run of the cross-database check, with no conditions.
tests/integration/test_v2_catalog_installed.py,tests/integration/test_v2_catalog_publication_qualification.py, their steps incatalog-runtime-integration, and theRUN_V2_CATALOG_COMPATIBILITYandRUN_V2_CATALOG_PUBLICATION_QUALIFICATIONswitches, which nothing else read. "Cross-database integration tests" keeps its single job,catalog-runtime-integration("MySQL, PostgreSQL, and Redis integration");pr.yml,push.yml, "CI complete" and.github/release_commit.pyare unchanged.tests/integration/test_v2_catalog_installed_folders.py, with--durations=10):extract_installed_catalog()does, and givesextract_cataloga reduced view of each. The view keeps the real model identity, package and release manifest, only the national region, no variables, and only the parameters and parameter nodes under the folders below.1,1.0andtrueapart.tests/fixtures/v2_catalog_value_shapes.pycovers the shapes extraction accepts that the installed models don't hold (text, mappings, enums as values, NumPy scalars and others). It is published and read back bytest_v2_catalog_publication.py::test_publication_stores_every_value_shape_unchanged. The row comparison helpers both tests use moved totests/integration/catalog_rows.py.The selected folders
gov.irs.income.bracketSINGLE,JOINT,SEPARATE,HEAD_OF_HOUSEHOLD,SURVIVING_SPOUSE); the top bracket's thresholds are infinitegov.irs.payroll.social_securitygov.aca.family_tier_statesgov.aca.ineligible_immigration_statusesgov.irs.credits.premium_tax_credit.phase_outending_rate[0].amount, ...) whose upper brackets hold null valuesgov.states.ne.dhhs.child_care_subsidy.fpg_fractiongov.hmrc.income_tax.rates.ukgov.dwp.state_pension.triple_lockTogether that is 150 parameters and 2,913 parameter values (US 136 and 2,870, UK 14 and 43). The installed models hold integers, fractions, booleans, lists, infinities and nulls, and no plain text or mapping values. Enum names appear as breakdown keys and inside lists. Every value is open-ended or ends the day before the next one starts.
What this gives up
publish_catalog's additional memory while it publishes the complete catalog, whichtest_v2_catalog_publication_qualification.pymeasured withtracemalloc.seed-v2-database.yml,scripts/publish_v2_metadata_catalog.py), before each deploy job. That compares the full catalog with the stored rows on every release, but inserts the full catalog only when the .py version is new.test_v2_catalog_installed.pypinned (7,438 variables, 29,367 parameter nodes, 104,673 parameters, 1,196,139 parameter values, 4 datasets, 1,837 regions for the 6.11.1 bundle), and its other checks on the complete catalog: the dataset each US and UK region type defaults to, England's region filter, the US place fallback count, and that every model version is .py's version.Cost of loading the models
Importing
policyenginebuilds both country models; after that,policyengine.us.modelandpolicyengine.uk.modelare attribute reads. The test's first test uses only the loaded models, so--durationsreports their loading on its own.import policyenginetook 14.6 s)Before this change, over the last 13 successful pull request runs (2026-10-29 and 2026-10-30), "Cross-database integration tests / MySQL, PostgreSQL, and Redis integration" took 7.2 to 37.6 minutes (median 11.1). Its two full-catalog steps took 5.0 to 32.8 minutes of that; every other step together took 2.1 to 4.8 minutes (median 3.1).
Environment variables and secrets
CODECOV_TOKENpr.yml(jobv2-integration-check) andpush.yml(jobv2-integration-check) pass it explicitly assecrets: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}; the reusable workflow declares it as an optionalworkflow_callsecret. Aworkflow_dispatchrun reads the repository secret directly. Unchanged.V2_MIGRATION_DATABASE_URL,V2_ALEMBIC_DISPOSABLE_TESTtests/integration/conftest.py'sdisposable_v2_database_urlenv:; the URL points at the job's ownpostgres:17serviceUV_PYTHON,ALEMBIC_DATABASE_URL,DEPLOYMENT_ENVIRONMENT,RUNTIME_CACHE_TEST_URLenv:POLICYENGINE_SKIP_COUNTRY_IMPORTSimport policyengine(country models load unless it is"1")No other variable is read on the new test's path. The full-catalog switches
RUN_V2_CATALOG_COMPATIBILITYandRUN_V2_CATALOG_PUBLICATION_QUALIFICATIONare gone.Testing
Run individually, by file or node ID (no full suite):
tests/integration/test_v2_catalog_installed_folders.pyagainst a localpostgres:17(four tests, including a missing-folder failure)tests/integration/test_v2_catalog_publication.py::test_publication_stores_every_value_shape_unchanged; it fails when one expected value is changed from12000.0to12000tests/unit/test_v2_integration_workflow.py(replacestest_full_catalog_integration_workflow.py): one job, no conditional step, no schedule, no full-catalog test, file or switch, and the new step after the role checkstests/unit/v2/test_catalog_value_shapes.pytests/unit/test_alembic_workflows.py::test_reusable_v2_integration_check_uses_disposable_databases_and_coverage(onecoverage run --branch, sevencoverage run -a --branch)tests/unit/test_locked_test_environments.py::test_detects_every_known_test_job(EXPECTED_TEST_JOBSback tocatalog-runtime-integrationonly) andtest_test_job_selects_the_production_python_version[v2-integration-check.yml:catalog-runtime-integration]python scripts/run_quality_guards.py(all guards pass) andpython -m scripts.rules render(no changes;rules/registry.tomlnames neither deleted test)🤖 Generated with Claude Code