Repository navigation
Conversation
This was referenced Nov 3, 2026
anth-volk
force-pushed
the
manifest-supported-years
branch
from
November 3, 2026 15:07
e1f5d73 to
3d1a05b
Compare
anth-volk
added a commit
that referenced
this pull request
Nov 3, 2026
On Python 3.11 to 3.13, coverage.py 7.13.5 records coverage with its C trace function (it uses sys.monitoring only on 3.14), so the Test jobs there take 65 to 90 minutes, and one of them was often cancelled at the 90-minute limit with no failing test: 3.12 on #730, 3.11 on #735. The 3.14 job takes 47 to 60 minutes. The push-to-main Test job runs the same suite and keeps the same limit as the pull-request one, so a release run isn't cancelled before Versioning either. Fixes #736 Co-authored-by: Anthony Volk <14987227+anth-volk@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
force-pushed
the
supported-years
branch
from
November 3, 2026 19:29
07af7b2 to
dc1a825
Compare
anth-volk
force-pushed
the
manifest-supported-years
branch
from
November 3, 2026 19:31
3d1a05b to
80e0490
Compare
The bundle manifest is to record each country's supported years on the certified dataset record, certification is to compute them on the certified bytes under the pinned packages, and create_datasets and ensure_datasets are to check requested years against them before any download and before reusing year files. The real-dataset test now compares the recomputed years with the manifest's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Certification records the certified dataset's supported years on data_releases.<country>.certified_data_artifact.supported_years. It downloads the certified file (reusing a verified copy) and computes the years with dataset_years.supported_years in a uv run --isolated environment holding exactly the certified model, the core and, for the US, the bundle's spm-calculator. bundle.py record-supported-years records them for the current certificate; bundle.py check and CertifiedDataArtifact refuse a malformed record. create_datasets and ensure_datasets check years requested for the certified dataset against the record before any download and before reusing year files, without reading the source. Other datasets and certificates without the record keep the check computed from the source. The US record is 2022-2035, computed on populace_us_2024 (sha256 6496cc43...) under policyengine-us 2.2.1, policyengine-core 3.33.3 and spm-calculator 1.0.0. The UK record is not filled in: the certified UK file could not be downloaded with the credentials available. Both TRACE sidecars are regenerated, since they bind the manifest's bytes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Computed with `bundle.py record-supported-years --country uk` on the certified microcosm_uk_2024_25 file: 2024 to 2032. The TRACE sidecars are regenerated to bind the updated manifest. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#730 now refuses US years before the data year, so the shipped US record is to start in 2024, and the certified-dataset test expects the computed US years to start in 2024. The stand-in US years in the certification and recording tests now start in 2024 too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With #730 refusing US years before the data year, bundle.py record-supported-years --country us now records 2024-2035 for the certified populace_us_2024 (sha256 6496cc43...) under policyengine-us 2.2.1, policyengine-core 3.33.3 and spm-calculator 1.0.0. The UK record (2024-2032) is unchanged. Both TRACE sidecars are regenerated with bundle.py generate --include-tros --strict-tros, since they bind the manifest's bytes; only the manifest digest and the composition fingerprint change. The UK sidecar was built from the certified UK release manifest bytes (sha256 1ebdbcc3...) through POLICYENGINE_UK_DATA_MANIFEST_FILE. The docs and changelog fragments give the new US years, and the changelog now also gives the UK record, which an earlier commit filled in. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
force-pushed
the
manifest-supported-years
branch
from
November 3, 2026 22:12
80e0490 to
3151eee
Compare
This branch has not been 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 #734
Builds on #730 (issue #729), which is merged into
main.Summary
#730 checks requested years with
supported_years(country_id, dataset_path), which needs the source file. Socreate_datasetscould download before refusing a year, andensure_datasetsreused year files that already exist without any check. This PR records the certified dataset's supported years in the bundle manifest and checks requests for that dataset against the record, reading no dataset or year file.The record
data_releases.<country>.certified_data_artifact.supported_years, a JSON list of integer years sorted ascending without duplicates. That is the shapesupported_yearsreturns and the execution receipt'ssupported_yearsuses.certified_data_artifact: the years belong to one file under one model. That record already names the file (dataset,uri,sha256,build_id), andcertificationnames the model. A top-level field would not say which of the release'sdatasetsit covers. The UK release also routes local areas tomicrocosm_uk_2024_25_dense, and the US release routes them topopulace_us_2024_acs_local.populace_us_2024@populace-us-2024-spm-20260915(sha2566496cc43…)python scripts/bundle.py record-supported-years --country us: policyengine-us 2.2.1, policyengine-core 3.33.3 and spm-calculator 1.0.0 in auv run --isolatedenvironment. The in-processsupported_yearson the locked environment gives the same list.microcosm_uk_2024_25@microcosm-uk-2024-25-national-20261025T091414Z-a6299504(sha256b96a8cd6…)python scripts/bundle.py record-supported-years --country ukon the certified file, downloaded with a token that can readpolicyengine/populace-uk-private, thenpython scripts/bundle.py generate --include-troswith the same token.The US record starts at the data year because #730 now refuses US years before it: society-wide runs no longer accept 2022 or 2023 for
populace_us_2024, which holds almost no data for them. An earlier version of this PR recorded 2022–2035.How the record is produced and checked
certify_data_release, sobundle.py certify-dataand the UK candidate workflow'sprepare) now writes the record. It makes the certified default dataset available as the runtime does, reusing a verified copy in./dataor downloading it and checking itssha256. It refuses a dataset without a certifiedsha256. It then runsdataset_years.supported_years_in_environment, which loadsdataset_years.pyby path in a throwawayuv run --isolated --no-project --no-configenvironment with exactly the certified model, the core (--core-versionor the bundle pin) and, for the US, the bundle's spm-calculator. The environment's imported versions are checked against those pins. This mirrors the regional input-surface audit's isolated environment. It matters because the UK candidate workflow certifies from an environment that still holds the previous model. Certification now needsuvand PyPI access, and downloads the certified file.bundle.py record-supported-years --country <country> [--data-dir DIR]records the years for the current certificate under the bundle's own pins, without re-certifying. That is how the US value above was written.bundle.py check(run by the "Verify release inputs and bundle packages" job and by the certification workflow) refuses a malformed record viabundle_validation.validate_supported_years. A missing record passes, because certificates from before it fall back to the computed check. The runtime modelCertifiedDataArtifact.supported_years(list[StrictInt]) applies the same check.*.trace.tro.jsonldfiles bind the manifest's bytes, so both were regenerated withbundle.py generate --include-tros --strict-trosafter each record was written, last after the US years were re-recorded. Only the manifest digest and the composition fingerprint change. The UK one was regenerated from the certified UK release manifest bytes, which match the sidecar's pin (1ebdbcc3…), viaPOLICYENGINE_UK_DATA_MANIFEST_FILE.bundle.py check --published-spm --include-tros --strict-trospasses.certificate_sha256(data_releases.us)).How the year check now runs
dataset_years.recorded_supported_years(country_id, dataset=None)returns the record when the request is the certified default: no dataset, its name, or its certified URI. The bundle must also serve that name with the certifiedsha256. Otherwise it returnsNone.create_datasetschecks every request the record covers before anymaterialize_datasetcall, so before any download. Requests it doesn't cover keep Refuse dataset years the country model does not project to #730's computed check after the source is local.ensure_datasetschecks the covered requests before deciding to reuse or create year files, so an existing year file for an unsupported year of the certified dataset is refused. That includes a US year file an earlier release created. No source or year file is read.allow_unsupported_years=Trueturns off both checks.Consumers of the manifest
policyengine_api/constants.py) reads the wheel'smanifest.jsonas a plain dict with.getand takes only named keys. The v2 catalog reads attributes of .py's ownCountryReleaseManifest, which ignores unknown fields. No JSON-schema orextra="forbid"validation of the manifest was found, so an unknown field is ignored.release_bundle.py,routing_publisher/bundles.py,stage12_bundle/parsing.py) reads named keys from the dict or fromget_release_manifest. Itsextra="forbid"models (Stage12CountryBundleand others) are built from those selected values, not from the raw manifest, so an unknown field is ignored. Its stage 12 bundle digest covers only the normalized values, so it does not change.Tests
tests/test_recorded_supported_years.py:validate_supported_yearsand bybundle.py check;record_supported_yearsand its command.tests/test_dataset_years.py:POLICYENGINE_UK_DEFAULT_DATASETorPOLICYENGINE_US_DEFAULT_DATASETis set. It also refuses a file whose sha256 is not the certified one and an installed model other than the pinned one.tests/test_certify_data_release.py,tests/test_uk_qualification_pipeline.py) stand in for the new computation, which would download data and install packages.tests/test_recorded_supported_years.py: 35 passed;tests/test_dataset_years.py: 65 passed, 2 skipped;test_the_recorded_years_equal_the_years_computed_on_the_certified_dataseton the certified files:[us](sha2566496cc43…) 1 passed,[uk](sha256b96a8cd6…) 1 passed;bundle.py check --published-spm --include-tros --strict-trospasses;ruff format --check .andruff check --ignore UP038 .pass;mypy --python-version 3.13 src/policyengine: 212 errors.🤖 Generated with Claude Code