Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/551.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Use the ACS-local Populace dataset by default for US state and congressional-district simulations while retaining the sparse Populace dataset as the national default.
16 changes: 11 additions & 5 deletions docs/bundles.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,14 +143,20 @@ python scripts/bundle.py certify-data \
--country us \
--data-producer populace \
--manifest-uri hf://dataset/policyengine/populace-us@<release>/releases/<release>/release_manifest.json \
--regional-manifest-uri hf://dataset/policyengine/populace-us@<local-area-release>/releases/<local-area-release>/release_manifest.json \
--model-version <policyengine-us-version>
```

US state and congressional-district regions scope the certified national
Populace dataset with row filters. If a Populace release also publishes derived
`states/*.h5` or `districts/*.h5` area slices, the bundle certification omits
those slices from `data_releases.us.datasets`; they are not runtime dataset
dependencies.
US state and congressional-district regions scope one certified ACS-local
Populace dataset with row filters. Pass its non-default local-area release
manifest through `--regional-manifest-uri`; certification adds the pinned H5
artifact to `data_releases.us.datasets` and writes both regional path templates
under `data_releases.us.region_datasets`. If a legacy release publishes derived
`states/*.h5` or `districts/*.h5` slices, certification still omits them.

`policyengine bundle install` continues to materialize only each country's
certified national `default_dataset`. Regional runtimes materialize the
additional certified dataset when the selected region declares it.

Use `python scripts/bundle.py generate` to regenerate derived bundle metadata,
and `python scripts/bundle.py generate --include-tros` when TRACE TRO sidecars
Expand Down
140 changes: 62 additions & 78 deletions docs/engineering/runbooks/build-m-us-populace-certification.md
Original file line number Diff line number Diff line change
@@ -1,112 +1,108 @@
# Build M US Populace certification runbook
# US Populace certification runbook

Fill-in-the-id runbook for certifying the next US Populace default
(`sparse-rmloss100` lineage: Build I → J → **M**) into the
`policyengine.py` bundle. It replays the exact steps that landed
[#470](https://github.com/PolicyEngine/policyengine.py/pull/470) (the Build J
certification), parameterized for the Build M release id. Read the
[data certification](../skills/data-certification.md) skill first for the
validation semantics; this file is the concrete checklist.
Use this runbook to certify a new national US Populace release together with
the shared ACS-local release used for state and congressional-district
simulations. Read the [data certification](../skills/data-certification.md)
skill first for validation semantics.

This historical filename is retained so existing links remain valid; the
procedure itself is release-independent.

## When to use

A new US Populace `sparse-rmloss100` release has been published to
`policyengine/populace-us` and is ready to become the certified default. You
have the release id, the release manifest is reachable, and the model version
it was built with is known.
Both release manifests have been published to `policyengine/populace-us`, and
the model version used by the national release is known. The national release
will remain the default dataset; the local-area release will remain
non-default and be selected only for supported regional runs.

## Prerequisites

- A clean worktree branched from current `origin/main`
(`git fetch origin && git checkout -b certify-us-buildm origin/main`).
- A clean worktree branched from current `origin/main`.
- Network access: certification fetches the release manifest and PyPI wheel
metadata and runs reachability `HEAD` checks against Hugging Face.
- `HUGGING_FACE_TOKEN` (or `HF_TOKEN`) exported — required to regenerate the
UK TRO in the `--include-tros` step and to run the UK data-release fetch in
the test suite. The US populace repo is public.

## Fill in these three values
## Step 1 — identify the releases

Set values from the two published release manifests rather than copying an
older certification:

```
BUILD_M_RELEASE_ID = populace-us-2024-buildm-sparse-rmloss100-<sha>-<timestamp>Z
MODEL_VERSION = 1.764.6 # policyengine-us Build M was built with
CURRENT_RELEASE_ID = populace-us-2024-buildj-sparse-rmloss100-75d5add-20260710T094201Z
NATIONAL_RELEASE_ID = populace-us-2024-<national-build>-<sha>-<timestamp>Z
LOCAL_AREA_RELEASE_ID = populace-us-2024-<local-build>-<sha>-<timestamp>Z
MODEL_VERSION = <policyengine-us version declared by the national release>
```

`CURRENT_RELEASE_ID` is the outgoing default (Build J) — the string you are
replacing in the pinned test constants. `MODEL_VERSION` stays `1.764.6` unless
Build M was built against a newer `policyengine-us`; if it was, see step 4.
The local-area manifest must declare `dataset_role: non_default_local_area`,
`is_default: false`, no default datasets, and exactly one pinned H5 microdata
artifact.

## Step 1 — certify the release
## Step 2 — certify both releases

```bash
python scripts/certify_data_release.py \
python scripts/bundle.py certify-data \
--country us \
--data-producer populace \
--model-version "$MODEL_VERSION" \
--manifest-uri "hf://dataset/policyengine/populace-us@$BUILD_M_RELEASE_ID/releases/$BUILD_M_RELEASE_ID/release_manifest.json"
--manifest-uri "hf://dataset/policyengine/populace-us@$NATIONAL_RELEASE_ID/releases/$NATIONAL_RELEASE_ID/release_manifest.json" \
--regional-manifest-uri "hf://dataset/policyengine/populace-us@$LOCAL_AREA_RELEASE_ID/releases/$LOCAL_AREA_RELEASE_ID/release_manifest.json"
```

This one command:

- rewrites `data_releases.us` in `src/policyengine/data/bundle/manifest.json`
from the Build M release manifest (default dataset, per-artifact
from the national release manifest (default dataset, per-artifact
repo/revision/sha256 pins, certified artifact, certification block);
- runs `generate(check=False)`, which re-normalizes `manifest.json` and
updates `pyproject.toml` **only if the model pins moved**;
- writes the changelog fragment
`changelog.d/certify-us-$BUILD_M_RELEASE_ID.changed.md`.
`changelog.d/certify-us-$NATIONAL_RELEASE_ID.changed.md`.

## Step 2 — regenerate the US TRO sidecar
## Step 3 — regenerate TRACE sidecars

The certify step does not touch TRO sidecars. Rebind them so
`src/policyengine/data/bundle/us.trace.tro.jsonld` records the new
`manifest.json` sha256 (the `bundle_manifest` artifact hash is asserted by
`tests/test_certify_data_release.py::TestVendoredSidecarBinding`):
The certify step does not touch TRACE sidecars. Regenerate them so they record
the new bundle-manifest SHA-256:

```bash
HUGGING_FACE_TOKEN="$HUGGING_FACE_TOKEN" python scripts/bundle.py generate --include-tros
```

Only `us.trace.tro.jsonld` should change (UK regenerates identically because
only US was certified). If UK cannot be reached, the run writes a *limited* UK
TRO — do not commit a degraded `uk.trace.tro.jsonld`; `git checkout` it and
rerun with a valid token.
Both country sidecars contain the bundle-manifest hash, so both may change when
the bundle changes. If UK cannot be reached, the run writes a *limited* UK
sidecar; do not commit that degraded output.

## Step 3 — update the pinned test constants
## Step 4 — update pinned expectations

Three files hard-code the certified release id. Replace `CURRENT_RELEASE_ID`
with `BUILD_M_RELEASE_ID` in each (this is the whole of #470's test diff):
Update tests that intentionally pin the outgoing national release, local-area
release, model version, or artifact hashes. Derive every replacement from the
new manifests; do not copy identifiers from this runbook.

- `tests/test_release_manifests.py` — `US_DATA_RELEASE_ID`.
- `tests/test_models.py` — the `us_latest.default_dataset_uri` `@<id>`
assertion.
- `tests/test_us_regions.py` — the national `dataset_path` `@<id>` assertion.
If the model version changed, refresh the household snapshots with:

## Step 4 — only if the model version changed

Build J → M on the same `policyengine-us` needs nothing here (this is the
common case; #470 left `pyproject.toml` and the snapshots untouched). If Build
M was built against a newer `policyengine-us`:
```bash
PE_UPDATE_SNAPSHOTS=1 pytest tests/test_household_calculator_snapshot.py
```

- `pyproject.toml` model pins are already rewritten by step 1's `generate`;
commit them.
- Update `US_MODEL_VERSION` and `US_BUILT_WITH_MODEL_VERSION` in
`tests/test_release_manifests.py`.
- Refresh the household snapshots:
`PE_UPDATE_SNAPSHOTS=1 pytest tests/test_household_calculator_snapshot.py`
and commit `tests/fixtures/household_calculator_snapshots/`.
## Step 5 — certify and verify the local-area release

## Step 5 — verify the local-area overlay survived
The certification command passes the immutable ACS-local release manifest with
`--regional-manifest-uri`. Confirm all of the following:

Certification rewrites only `data_releases.us`, so the non-default
`dataset_overlays.us.populace_us_2024_acs_local` entry (see
[Non-default dataset overlays](../../release-bundles.md#non-default-dataset-overlays))
must still be present and resolvable. No manual re-add is needed — confirm it:
- `default_dataset` remains the national Populace dataset;
- the local-area artifact appears in `data_releases.us.datasets` with its
repository type, immutable revision, and SHA-256;
- `region_datasets.national` selects the national artifact;
- `region_datasets.state` and `region_datasets.congressional_district` select
the shared local-area artifact;
- no derived `states/*.h5` or `districts/*.h5` artifacts are runtime inputs.

```bash
python -c "import json; b=json.load(open('src/policyengine/data/bundle/manifest.json')); assert 'populace_us_2024_acs_local' in b['dataset_overlays']['us'], 'overlay lost'; print('overlay preserved')"
pytest tests/test_release_manifests.py -k "local_area or DatasetOverlays" -q
pytest tests/test_certify_data_release.py \
tests/test_release_manifests.py \
tests/test_us_regions.py \
-q
```

## Step 6 — check, format, lint, test
Expand All @@ -118,28 +114,16 @@ make lint
make test # needs HUGGING_FACE_TOKEN for UK
```

## Step 7 — commit exactly these files

Matches #470's file set (add `pyproject.toml` and the snapshot dir only when
step 4 applied):
## Step 7 — inspect and commit the generated changes

- `src/policyengine/data/bundle/manifest.json`
- `src/policyengine/data/bundle/us.trace.tro.jsonld`
- `changelog.d/certify-us-$BUILD_M_RELEASE_ID.changed.md`
- `tests/test_release_manifests.py`
- `tests/test_models.py`
- `tests/test_us_regions.py`
The expected diff normally includes the bundle manifest, TRACE sidecars, one
Towncrier fragment, and pinned test expectations. Include package pins and
snapshots only when the certified model version changed. Investigate any other
generated difference before committing it.

## Step 8 — open the PR

Follow [github-prs](../skills/github-prs.md): open/find the issue, put
`Fixes #ISSUE` first, push to the canonical repo, and open a **draft** PR. The
certify step already wrote the changelog fragment, so the changelog check
passes.

## Verified against #470

Every step above is checked against the merged Build J certification (#470),
whose diff was exactly: `manifest.json`, `us.trace.tro.jsonld`, the three test
constants, and the auto-written changelog fragment — with `pyproject.toml` and
the snapshots untouched because `policyengine-us` stayed `1.764.6`.
27 changes: 19 additions & 8 deletions docs/engineering/skills/data-certification.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,30 @@ For US Populace certification, certify the Populace release manifest directly:
```bash
python scripts/bundle.py certify-data --country us --data-producer populace \
--manifest-uri "hf://dataset/policyengine/populace-us@<tag>/releases/<tag>/release_manifest.json" \
--regional-manifest-uri "hf://dataset/policyengine/populace-us@<local-area-tag>/releases/<local-area-tag>/release_manifest.json" \
--model-version "<policyengine-us-version>"
```

US state and congressional-district regions are row filters over the certified
national Populace dataset. Certification writes:
US state and congressional-district regions are row filters over one shared,
certified ACS-local Populace dataset. Its release manifest must declare
`dataset_role: non_default_local_area`, `is_default: false`, no default
datasets, and exactly one pinned H5 microdata artifact. Certification writes:

```json
"region_datasets": {
"national": {"path_template": "populace_us_2024.h5"}
"national": {"path_template": "populace_us_2024.h5"},
"state": {"path_template": "populace_us_2024_acs_local.h5"},
"congressional_district": {"path_template": "populace_us_2024_acs_local.h5"}
}
```

The ACS-local artifact is a second entry in `data_releases.us.datasets`; it is
not a dataset overlay and it never replaces the national `default_dataset`.

If the Populace release publishes derived `states/*.h5` or `districts/*.h5`
files for compatibility checks, certification omits them from the runtime
bundle. The national H5 is the canonical `.py` dataset.
bundle. The country-wide default and ACS-local dataset are each single shared
files; region registries select one and then filter its rows.

The script fetches and validates the manifest (every artifact must carry a
revision pin; the certified dataset must be reachable), writes the canonical
Expand Down Expand Up @@ -74,8 +83,9 @@ A certification PR should normally change only:
Hard failures (certification refuses): missing national default dataset,
default dataset absent from artifacts, any artifact without a revision pin,
unreachable certified dataset, missing required supplemental release files
(for example Populace-US `us_source_coverage.json`), missing or malformed US
state overlay artifacts when `--regional-manifest-uri` is used, unknown country.
(for example Populace-US `us_source_coverage.json`), a malformed shared
local-area release or malformed legacy per-state artifacts when
`--regional-manifest-uri` is used, unknown country.

Certification gate: the model version must either exactly match the
build-time model (`compatibility_basis: built_with_model_package`) or be
Expand All @@ -92,8 +102,9 @@ publisher-claim basis above.

Concrete, fill-in-the-id runbooks that replay a specific certification live
under `docs/engineering/runbooks/`. See
`runbooks/build-m-us-populace-certification.md` for the next US Populace
`sparse-rmloss100` default.
`runbooks/build-m-us-populace-certification.md` for the reusable US national
and local-area certification procedure. The historical filename is retained
so existing links remain valid.

## Legacy paths

Expand Down
11 changes: 6 additions & 5 deletions docs/microsim.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,15 +134,16 @@ pe.us.load_datasets() # or pe.uk.load_datasets()

### US local-area dataset

Alongside the certified national default, the bundle registers a **non-default**
US dataset for finer geographic work: `populace_us_2024_acs_local`. It is a
Alongside the certified national default, the bundle registers a US dataset for
finer geographic work: `populace_us_2024_acs_local`. It is a
Populace US 2024 build of roughly **1.6 million households** on an **ACS 2024
multispine**, with each household **PUMA-assigned** to a 119th-Congress
congressional district, county, and state, and calibrated to **state
administrative totals and state and congressional-district population**. Its
release gate summary records **four reviewed limitations**, so read that gate
summary before relying on it. It ships in its own immutable release and is never
selected implicitly — you load it by name.
release validation summary records **four reviewed limitations**, so read that
summary before relying on it. It ships in its own immutable release. State and
congressional-district region simulations select it through the bundle's
`region_datasets` metadata; direct microsimulations can still load it by name.

Two-line load:

Expand Down
15 changes: 9 additions & 6 deletions docs/regions.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,19 @@ ca_snap = Aggregate(
ca_snap.run()
```

Each state is a region in the US registry. State regions scope the certified
national Populace dataset by `state_fips`; they do not require separate state
H5 files:
Each state is a region in the US registry. State regions load the ACS-local
Populace dataset declared by `region.dataset_path`, then scope its rows by
`state_fips`. They do not require separate state H5 files:

```python
states = pe.us.model.region_registry.get_by_type("state")
for region in states:
print(region.code, region.label, region.scoping_strategy)
```

For state-specific simulations, pass `scoping_strategy=region.scoping_strategy`
with the certified national dataset.
For state-specific simulations, use both `region.dataset_path` and
`region.scoping_strategy`. The regional simulation API performs both steps from
the registry entry.

## US congressional districts

Expand All @@ -49,7 +50,9 @@ for row in impacts.district_results:
print(row["district_geoid"], row["avg_change"], row["winner_percentage"])
```

`district_geoid` is the SSDD integer (state FIPS × 100 + district number; at-large districts use `00`). Congressional district regions scope the certified national Populace dataset by `congressional_district_geoid`.
`district_geoid` is the SSDD integer (state FIPS × 100 + district number;
at-large districts use `00`). Congressional district regions load the same
ACS-local file and scope its rows by `congressional_district_geoid`.

## UK parliamentary constituencies

Expand Down
Loading
Loading