Repository navigation
Bake per-state ACS-local year files into Stage 12 and record the dataset state runs load - #885
Merged
Merged
Conversation
anth-volk
force-pushed
the
feat/stage12-state-datasets
branch
from
October 21, 2026 20:50
fca6036 to
416e53d
Compare
anth-volk
force-pushed
the
feat/state-datasets
branch
from
October 21, 2026 21:47
9eb6790 to
aaa97c8
Compare
anth-volk
force-pushed
the
feat/stage12-state-datasets
branch
from
October 21, 2026 21:51
1235a0e to
3a28ef6
Compare
Stage 12 gets its own copy of the per-state dataset identity, without importing the main path's precompute modules. Stage12StateDatasetCacheIdentity (schema stage12-sds1) holds a dataset identity's fields for the regional dataset (its own SHA-256 and artifact revision from the published Stage 12 bundle, the package versions and the bundle manifest digest) plus the state code and FIPS and the filter variable. Its store path is state-datasets/<country>/<digest>/<stem>_year_<year>.h5. stage12_cache/state_datasets.py places each state's files at <Stage 12 data folder>/state-datasets/<dataset>/<STATE>. The national dataset and baseline identities are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Stage 12's precompute gets its own state_dataset_targets, which resolves every US state region the way a Stage 12 worker resolves a request for it and keeps the states whose dataset is not the bundle default, with their row filter and state code. The plan lists one StateDatasetPlanEntry per precompute year and target state, year-major and by state code, with its key, store path, file name, image folder and presence in the bucket; select_work keeps the missing ones. On the installed bundle that is 51 states for each of the three years, all on the ACS-local dataset. Nothing builds or publishes these entries yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Stage 12's own build_state_datasets_impl mirrors the main path's: it re-derives each planned state's key from the installed Stage 12 bundle and refuses to build on a mismatch, has .py prepare the regional dataset's full-country year file once, collects garbage and reloads the year, refuses data in which a household's district code names another state, then for each state writes the rows its region's own scoping strategy keeps with .py's save(), copies the year-file stamp, confirms .py's reuse checks accept the file, and uploads it to the write-once Stage 12 cache, which checks the stored digest and size. Stage 12 keeps its own copy of the reuse check. The fake GCS blob gains upload_from_filename, the first test of a file upload on the Stage 12 side. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Stage 12 precompute app gains build_state_datasets (8 CPUs, 96 GiB, two hours), one call per year, validating plan entries in and dumping results out. run_precompute starts the state builds with the dataset builds and waits for them only after the determinism check, before publishing the manifest, so baselines never wait for them, then reports how many were built and uploaded and their total size. The determinism record still covers baselines only. The manifest does not list the state datasets yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Stage 12 cache manifest model accepts state_dataset entries, with their folder and state code, in their own model chosen by "type", so dataset and baseline entries keep their wire shape. The image fetch now checks every entry before downloading anything: it refuses unknown types, state datasets that do not cover the same states in every year, unsafe folders and file names, and two entries for one file (by folder and name, so every state's same-named file can coexist), and places each state file in its folder. The worker check expects the 63 national files plus one file per year for each state the installed bundle maps to a non-default dataset, and requires every listed state file on disk; the release it reports keeps today's fields. No manifest lists state datasets yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
build_manifest appends a state_dataset entry, with its folder, state code and the stored digest and size, for every planned state file after the datasets and baselines. A plan without state datasets publishes the manifest it always did. The Stage 12 image fetch places each state file in its folder, and the worker check expects them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Stage 12's worker asks its own copy of the baked-folder lookup, in stage12_cache/state_datasets.py, for the Stage 12 image folder of the calculation's state before loading a non-default dataset, and passes it to _load_dataset. The lookup returns the folder only when the image holds that state's year file for the year and .py's reuse checks accept it, so ensure_datasets never rebuilds the regional dataset inside a baked folder; otherwise the calculation prepares the dataset as before. District calculations read their state's file and keep their district filter. National, region-group and UK calculations are unchanged. The selection-contract test now uses real RegionResolution and DatasetSelection values. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main-path US state and district runs load a non-default dataset (the ACS-local dataset since .py 6.7), but their results named the default dataset's release as data_version, because the runtime passed no resolved data version and the year file carries none. The runtime now passes the revision the .py release manifest gives that dataset (populace-us-2024-buildo-acs-local-... for 6.7.5). National runs and every run on the default dataset report the release's data version as before. Stage 12 takes data_version from its dataset provenance; once state runs record ACS-local there, both paths report the same value for them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Stage12CountryBundle gains region_datasets: for each region type in .py's
region_datasets, the identity of the bundle dataset its path names, or None
for a per-region file pattern such as states/{state_code}.h5; a path that
names no bundle dataset is refused. Bundles published before the field
have None. On the installed 6.7.5 bundle, state and congressional_district
regions load populace_us_2024_acs_local and national regions
populace_us_2024.
Entry services already running forbid unknown fields in the manifest they
read, so the v2 version manifest now goes under three keys:
active-with-region-datasets holds it all, active-with-cache keeps its
current shape without region datasets, and active keeps its shape without
cache metadata either. Loaders read the newest key a publish has written,
and a first publish keeps the versions stored under the older keys.
Adding the field changes the Stage 12 bundle digest, which keys every
Stage 12 cache file, so the first deploy rebuilds the Stage 12 cache.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A Stage 12 worker now accepts a simulation whose provenance names the dataset the installed bundle gives its region type (state and congressional_district regions: the ACS-local dataset), with that dataset's URI and revision, as well as the default dataset. The default stays accepted for state and district runs because entry services released before regional provenance send it until they are updated; any other dataset, and a regional dataset for a national run, are refused as before. After resolving the region's dataset, the worker requires the provenance to name the dataset it loads, by name and URI, so a comparison record can no longer name one dataset while the calculation used another. The one accepted difference is default provenance on a run that loads a regional dataset, from those older entry services. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t runs The entry adapter now records, for a state or congressional-district request, the dataset the worker's published bundle names for that region type (the ACS-local dataset): its identity, URI and revision in the dataset and bundle provenance, and its URI and SHA-256 as the population artifact. A bare two-letter US region counts as a state, as the gateway reads it. The entry service keeps its own copy of the worker's region-type reading. National and UK requests, and requests to workers whose manifest predates region datasets, still name the default dataset, and the request's data value is still checked against the default. Workers accept regional provenance since the previous commit, so they never refuse what this sends. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adding region_datasets to the bundle changed bundle_digest for every bundle. A deploy replaces the running v2 application, whose name depends only on the .py version, before the new version manifest is published, and entry services send the digest they read from that manifest; until the publish, every comparison run would have been refused with "installed bundle digest differs", and the Stage 12 cache, keyed by the digest, would have been rebuilt. region_datasets comes from the same .py bundle whose version the digest already covers, so the digest now leaves it out. The installed 6.7.5 bundle keeps the digest it had before this change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Stage 12 worker and the entry adapter each kept a copy of the region-type reading, and neither ignored surrounding whitespace or upper case as the runtime's region normalisation does: for a region of State/UT the entry sent default provenance while the worker loaded the ACS-local dataset, hidden only by the temporary acceptance of the default. The contract library now has one region_type_of, matching the runtime's reading, and Stage12CountryBundle.dataset_for_region, which both use. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The US worker image's Stage 12 cache fetch kept its 1,800 s limit while gaining a file per state for each precomputed year, downloaded and hashed one after another on two CPUs. It now allows 3,600 s, as the main path's fetch does for the same files. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Stage 12's copy of the per-state build gets the fixes made to the main path's: - it refuses only district codes that name a registered district of a different state, so an unassigned code such as 0 no longer stops the precompute and the deploy waiting on it; - a target without a row filter is refused before anything is written, and the target's strategy is typed as an optional RowFilterStrategy; - builds are grouped by year and dataset, since one build prepares one dataset's year file; - each result records how long the year's build had run, and the log reports per build the files built and uploaded, the bytes actually uploaded, and the build time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…on doc The Stage 12 worker foundation document said the cache manifest held all 63 files and described two manifest keys. It now describes the per-state datasets the precompute builds and the image places in state folders, the third manifest key that carries region datasets, the dataset provenance the entry service and worker now agree on, and why the bundle digest leaves region datasets out. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…datasets The cache release a US worker reports is now built by _cache_release_summary, and a test shows it still validates against Stage12CacheRelease, which pins the national counts and forbids other fields, when the installed manifest also lists state datasets. Another test shows UK regions keep requiring the default dataset when the bundle names dataset per region type. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Code released before region datasets publishes only the active-with-cache and active keys, so after a rollback the active-with-region-datasets copy is left out of date. Entry services from this change would have kept reading it, sending ACS-local provenance to the older workers, which refuse it, and the next publish would have dropped the worker versions the older code added. Readers and the publisher now use that copy only when, with its region datasets removed, it equals the manifest under active-with-cache; otherwise they read active-with-cache. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
region_type_of restates the runtime's region normalisation, so an executor test now runs both on the same codes (US and UK, bare codes, mixed case, surrounding spaces, prefixed codes). It found one difference: a bare "uk" requested as a US region was read as a state; another country's code now names no region type, as at run time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…its file When two bundle datasets have the same file path, region_datasets took the identity first in sorted order, so an alias listed for the default dataset's file would have become the national region's dataset and workers would then refuse national runs naming the default. The default dataset now owns its path; other collisions still take the first identity in sorted order. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A test only showed that the digest ignores region_datasets, so the next field added to the bundle could change every digest unnoticed, refusing comparison runs during a deploy and rebuilding the Stage 12 cache. The digest of a fixed bundle is now pinned to the value the code before region datasets gives it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Stage 12's copy of the baked-folder lookup now logs a warning and returns no folder when .py's year-file reuse checks, which import a private .py helper, cannot be imported after an upgrade, so state and district calculations prepare their dataset instead of failing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Stage 12's copy of the in-container checks now refuses a state target without a row filter before the full-country year file is prepared, and returns each state's row filter. The orchestration docstring says builds run one call per year and dataset. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Stage 12 worker foundation document said current readers read the newest key a publish has written. It now gives the actual rule (the region dataset copy only while it matches active-with-cache once region datasets are removed) and the one window it leaves on a rollback to code from before region datasets: until the older code publishes, entry services keep sending regional provenance, which the older worker refuses, failing Stage 12 comparison runs for state and district requests but no production response. The rollback step that avoids it is to delete the active-with-region-datasets key before deploying the older code. A comment in publish_v2_manifest now gives the right reason readers never combine parts of two documents. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pyright reads `Series.isin` as taking a sequence, mapping, Series or DataFrame, so it refused the set of registered district codes. The check now passes them sorted, which keeps the same matches. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
force-pushed
the
feat/stage12-state-datasets
branch
from
October 22, 2026 13:13
2da4cdc to
6b23b26
Compare
anth-volk
marked this pull request as ready for review
October 22, 2026 15:04
anth-volk
added a commit
that referenced
this pull request
Oct 22, 2026
Brings in main up to 1f59a56 (#885 and the rules, Pyright and locked-install work before it). Git merged every file without conflicts, including changelog_entry.yaml, which keeps both sides' entries. Checked after the merge: the contract (274 passed), gateway (261 passed) and entry (662 passed) suites and the quality guards pass. Two known failures remain, both fixed by the next commit: - The executor suite has 2 failures out of 1789, the two routed-national tests in test_simulation_output_builder.py. main's run now passes data_folder= to _load_dataset (for the baked state folders), and the tests' fake does not take that keyword: TypeError: ... got an unexpected keyword argument 'data_folder'. - The executor's Pyright check reports five reportPossiblyUnbound errors in _uk_area_simulations, which opens its spans with runtime.span(...) instead of scopes.span(runtime, ...). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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 #884
Rebased on
mainafter #879 merged.Same-Repository Draft PR Check
PolicyEngine/policyengine-sim-api, not a personal fork.Summary
Stage 12 per-state datasets
Stage 12 gets its own copy of #879's mechanism. Nothing in it imports the main path's precompute modules.
Content key
stage12-sds1and folder layout. The key is built from the regional dataset's entry in the published Stage 12 bundle, plus the state and filter. Files go instate-datasets/<dataset>/<STATE>under the Stage 12 data folder.Plan.
state_dataset_targets()resolves each state region the way a Stage 12 worker would resolve it. There is one entry per year and state.Build.
build_state_datasets_impl:Precompute run.
build_state_datasetsruns with 8 CPUs, 96 GiB and a two-hour limit, one call per year and dataset. The run waits for it only before publishing the manifest. For each build it logs the files built and uploaded, the bytes uploaded and the time taken.Image fetch and worker check. Every entry is checked before anything downloads:
The fetch timeout rises from 1,800 s to 3,600 s, matching the main path. The worker check expects 63 files plus three per state that uses a non-default dataset. The cache release it reports is unchanged.
Manifest. The manifest lists
state_datasetentries. A plan with no state files publishes exactly the same manifest as before.Runtime. Stage 12 state and district calculations read their state's baked file when it exists and .py would reuse it. Otherwise they prepare the dataset as before, including when an upgrade has moved the private .py helper the reuse checks import.
Dataset provenance and
data_versiondata_version. US state and district runs now report the loaded dataset's revision (the ACS-local revision) asdata_version, not the national release. National runs are unchanged.Stage12CountryBundle.region_datasetsnames the dataset each region type loads. A templated path such asstates/{state_code}.h5maps to none. A path that names no bundle dataset is refused.region_type_ofandStage12CountryBundle.dataset_for_regionread region codes the way the runtime normalises them. The worker and the entry adapter both use them.region_datasetsout, so the installed 6.7.5 bundle keeps the digest it has onmain.active-with-region-datasets. The keysactive-with-cacheandactivekeep their current shapes for entry services already running, whose models forbid unknown fields. Loaders read the newest key.Deploy effects.
data_versiondifference, because the main path now reports the ACS-local revision. This stops once the entry service is updated.active-with-cacheandactive, leaving theactive-with-region-datasetscopy out of date. Readers and the publisher use that copy only while it equals theactive-with-cachemanifest once its region datasets are removed. After the older code's publish, entry services stop sending regional provenance, and the next publish keeps the versions the older code added.active-with-region-datasetskey from thesimulation-api-v2-version-manifestModal Dict before deploying the older code. The migration document describes this.Follow-up: once every entry service sends regional provenance, remove the workers' acceptance of the default dataset for state runs.
Testing
uv run pytest tests/): 1,753 passed, 22 skipped;populace_us_2024_acs_local;review-code, each finding fixed test-first.python scripts/run_quality_guards.pypassed.ruff check .andruff format --checkwith ruff 0.15.22 are clean.python -m scripts.rules pyrightpasses for the executor, the contract library and the entry service, with the executor's errors matchingmain's baseline (77). The last commit passesisina list in Stage 12's district-code check. Norules/file changes.🤖 Generated with Claude Code