Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
79d620a
Record the file-set comparison and local check results
MaxGhenis Sep 11, 2026
d9ca5eb
Require Python 3.11 through 3.14 and regenerate the lock
MaxGhenis Sep 11, 2026
59931d2
Add core SPM selection, receipts, and run identity
MaxGhenis Sep 11, 2026
62d8eb9
Integrate canonical SPM and native entity data in the US model
MaxGhenis Sep 11, 2026
dba5599
Pin and validate canonical SPM settings in the release bundle
MaxGhenis Sep 11, 2026
d896f1d
Accept the repository-bundle TRACE emission context
MaxGhenis Sep 11, 2026
98dfc0d
Gate release publication on authenticated bundle provenance
MaxGhenis Sep 11, 2026
7fdf114
Document the canonical SPM contract and release checks
MaxGhenis Sep 11, 2026
f07048d
Record the opened draft PR and its CI results
MaxGhenis Sep 11, 2026
223bce4
Justify the SPM receipt dataset by its real reason
MaxGhenis Sep 11, 2026
e49e5e5
Record verified prerequisites for the canonical release
MaxGhenis Sep 12, 2026
a708019
Keep Populace rules armed for source-enrichment releases
MaxGhenis Sep 12, 2026
e14c7d2
Bind the wrapper to the published canonical tuple
MaxGhenis Sep 12, 2026
bccb603
Relock on the canonical tuple
MaxGhenis Sep 12, 2026
c6a99c4
Rebind the TRACE TROs to the canonical bundle
MaxGhenis Sep 12, 2026
bff2c0b
Record the published-wheel provenance blocker
MaxGhenis Sep 12, 2026
b0dee94
Retarget the legacy pin assertions at the canonical tuple
MaxGhenis Sep 12, 2026
81c2d26
Give the synthetic US fixtures the county the certified bundle requires
MaxGhenis Sep 12, 2026
78477e5
Declare national SPM geography in the reform-application fixtures
MaxGhenis Sep 12, 2026
1b72a31
Apply ruff formatting to the reform-application fixtures
MaxGhenis Sep 12, 2026
dbf1b1a
Record the final test state and the six blocked failures
MaxGhenis Sep 12, 2026
22dbde6
Rebuild the staged-pin premise by role, not by deletion
MaxGhenis Sep 12, 2026
e7bfa2b
Correct the characterisation of the SPM contract failure
MaxGhenis Sep 12, 2026
f7a73ee
Restate the lane brief against published 2.0.1
MaxGhenis Sep 12, 2026
e022f43
Record why the 2.0.1 repin is blocked on a publisher claim
MaxGhenis Sep 12, 2026
85b1d71
Follow the country's housing-cap contract for SPM geography
MaxGhenis Sep 12, 2026
456af5d
Regenerate the US model surface for the pinned country
MaxGhenis Sep 12, 2026
7467562
Refuse to rebaseline the SNAP annualization defect
MaxGhenis Sep 12, 2026
fc29be6
Record rulings A, C and D as done
MaxGhenis Sep 12, 2026
7019c9f
Pin down the SNAP defect with the country's own monthly values
MaxGhenis Sep 12, 2026
04960e6
Regenerate three US snapshots against two located country changes
MaxGhenis Sep 12, 2026
2019530
Correct the SNAP diagnosis and rebaseline the no-income case
MaxGhenis Sep 12, 2026
49a5289
Record rulings E and the reversal of D
MaxGhenis Sep 12, 2026
1b6c001
Drop a rounded sum a cent off the asserted value
MaxGhenis Sep 12, 2026
50004dd
Track the 2.2.1 repin lane in PROGRESS.md
MaxGhenis Sep 15, 2026
7b395e4
Certify populace-us-2024-spm-20260915 for policyengine-us 2.2.1
MaxGhenis Sep 15, 2026
d3a982b
Resolve the reviewed registry lock onto policyengine-us 2.2.1
MaxGhenis Sep 15, 2026
207895f
Regenerate the bundled TRACE sidecars for the repinned bundle
MaxGhenis Sep 15, 2026
88039b3
Restore the household acceptance rewrite for the 2.2.1 resource contract
MaxGhenis Sep 15, 2026
26a584a
Repoint the identity-fact test constants at the new certified pair
MaxGhenis Sep 15, 2026
f7894eb
Correct the resource-geography contract in the shipped prose
MaxGhenis Sep 15, 2026
625b413
Record the lane state and the corrected command sequence
MaxGhenis Sep 15, 2026
01ef3b5
Name the whole fail-closed chain, and correct the calculator pin in t…
MaxGhenis Sep 15, 2026
eaa95b4
Close out the lane log
MaxGhenis Sep 15, 2026
4abf0e6
Drop the lane progress log before release
Sep 15, 2026
d9e54e4
Say what this release ships, and pin all five fail-closed resource va…
Sep 15, 2026
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
21 changes: 13 additions & 8 deletions .github/workflows/pr_code_changes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ on:
- .github/**
- changelog.d/**
- pyproject.toml
- uv.lock
- src/policyengine/data/bundle/manifest.json
workflow_dispatch:

Expand Down Expand Up @@ -57,7 +58,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
python-version: ["3.11", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v6
- name: Set up Python ${{ matrix.python-version }}
Expand All @@ -68,16 +69,13 @@ jobs:
- name: Install uv
uses: astral-sh/setup-uv@v8.1.0
- name: Install package (no country-model extras)
# `h5py` is used transitively by policyengine.core.scoping_strategy
# but is normally supplied via the [us]/[uk] extras (through
# policyengine-core). Install it directly so the smoke import can
# exercise the wrapper without the country models, which pin
# versions that don't support 3.9/3.10 yet.
run: uv pip install --system . h5py
run: uv pip install --system .
- name: Smoke-import core modules
run: python -c "import policyengine; from policyengine.core import Dataset, Policy, Simulation; from policyengine.outputs import aggregate, poverty, inequality; print('import OK')"
BundleVerification:
name: Verify bundle metadata
# Private manifest credentials are available only to trusted repository PRs.
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
env:
POLICYENGINE_SKIP_COUNTRY_IMPORTS: "1"
Expand Down Expand Up @@ -113,14 +111,21 @@ jobs:
PY
- name: Check installed package consistency
run: python -m pip check
# Only the reviewed registry lock is a pull-request concern. The
# read-only credential, published-measurement and TRACE sidecar gates
# are release gates: the release workflow regenerates the sidecars and
# publishes the wheels immediately before checking them, so they cannot
# be satisfied from a pull request. They run in push.yaml instead.
- name: Check the reviewed registry lock
run: python scripts/release_lock.py
- name: Verify bundle packages
run: policyengine bundle verify --country us --country uk --packages-only --json
Test:
runs-on: macos-latest
strategy:
fail-fast: false
matrix:
python-version: ['3.13', '3.14']
python-version: ['3.11', '3.12', '3.13', '3.14']
steps:
- name: Checkout repo
uses: actions/checkout@v6
Expand Down
42 changes: 38 additions & 4 deletions .github/workflows/push.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ['3.13', '3.14']
python-version: ['3.11', '3.12', '3.13', '3.14']
steps:
- name: Checkout repo
uses: actions/checkout@v6
Expand Down Expand Up @@ -114,22 +114,39 @@ jobs:
fetch-depth: 0
- name: Fetch tags
run: git fetch --tags --force
- name: Install uv
uses: astral-sh/setup-uv@v8.1.0
- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: '3.13'
- name: Install package for TRO verification and regeneration
run: uv pip install -e . h5py --system
- name: Check reviewed release inputs before versioning
env:
HUGGING_FACE_TOKEN: ${{ secrets.HUGGING_FACE_TOKEN }}
run: |
if [[ -z "${HUGGING_FACE_TOKEN:-}" ]]; then
echo "::error::Full private release verification requires HUGGING_FACE_TOKEN"
exit 1
fi
python scripts/check_release_credentials.py
python scripts/bundle.py check --published-spm --include-tros --strict-tros
python scripts/release_lock.py
- name: Build changelog
run: pip install yaml-changelog towncrier && make changelog
- name: Generate derived bundle metadata
run: python scripts/bundle.py generate
- name: Refresh only the release version in the registry lock
run: python scripts/release_lock.py --refresh
- name: Preview changelog update
run: ".github/get-changelog-diff.sh"
- name: Install package for TRO regeneration
run: pip install -e . h5py
- name: Regenerate bundled TRACE TROs
env:
HUGGING_FACE_TOKEN: ${{ secrets.HUGGING_FACE_TOKEN }}
run: python scripts/bundle.py generate --include-tros
run: |
python scripts/bundle.py generate --include-tros --strict-tros
python scripts/bundle.py check --published-spm --include-tros --strict-tros
- name: Update changelog, bundle metadata, and TROs
uses: EndBug/add-and-commit@v9
with:
Expand Down Expand Up @@ -160,6 +177,17 @@ jobs:
- name: Capture published version
id: version
run: bash .github/capture-version.sh
- name: Validate complete bundle and registry lock before publication
env:
HUGGING_FACE_TOKEN: ${{ secrets.HUGGING_FACE_TOKEN }}
run: |
if [[ -z "${HUGGING_FACE_TOKEN:-}" ]]; then
echo "::error::Full private release verification requires HUGGING_FACE_TOKEN"
exit 1
fi
python scripts/check_release_credentials.py
python scripts/bundle.py check --published-spm --include-tros --strict-tros
python scripts/release_lock.py
- name: Publish a git tag
run: ".github/publish-git-tag.sh"
- name: Build package
Expand Down Expand Up @@ -200,10 +228,16 @@ jobs:
steps:
- name: Checkout repo
uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.13'
- name: Wait for release to be visible on PyPI
env:
VERSION: ${{ needs.Publish.outputs.version }}
run: bash .github/wait-for-pypi.sh
- name: Validate published SPM bundle before consumer updates
run: python -S scripts/bundle.py check --published-spm
- name: Generate GitHub App token
id: app-token
uses: actions/create-github-app-token@v1
Expand Down
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

A Python package for tax-benefit microsimulation analysis. Run policy simulations, analyse distributional impacts, and visualise results across the UK and US.

Requires Python 3.11–3.14.

> **Results are estimates.** PolicyEngine simulates a large, evolving body of tax-benefit law (the US model alone encodes more than 95,000 parameters across 5,500+ variables) over survey microdata calibrated to administrative targets. Treat outputs as estimates, and validate them against the policies relevant to your analysis, the scope of the rules engine, and external or back-of-the-envelope calculations. You can inspect the certified US dataset's calibration at https://calibration-diagnostics.vercel.app/populace.


Expand All @@ -26,13 +28,17 @@ print(uk.household.hbai_household_net_income) # net income
us = pe.us.calculate_household(
people=[{"age": 35, "employment_income": 60_000}],
tax_unit={"filing_status": "SINGLE"},
household={"state_code": "CA"},
household={"state_code": "CA", "county_fips": "06037"},
year=2026,
reform={"gov.irs.credits.ctc.amount.adult_dependent": 1000},
)
print(us.tax_unit.income_tax, us.household.household_net_income)
```

US default outputs require observed county FIPS or an explicit national/SPM-area
choice. See the [SPM household contract](docs/households.md#spm-geography-and-measurement-selection)
for settings, provenance and the coordinated bundle this release ships.

### Population analysis

```python
Expand Down
1 change: 1 addition & 0 deletions changelog.d/canonical-certification-guards.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Recognise the `microcosm-data` producer name and the `evidence` artifact kind when certifying a US data release, so source-enrichment releases keep the per-artifact reachability check and pin their release-directory sidecars at paths that resolve.
1 change: 1 addition & 0 deletions changelog.d/canonical-spm-bundle.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Validate independently pinned SPM bundle settings, verify published calculator wheel identities, and support explicitly uncertified local-wheel development fixtures ahead of the production promotion that follows this release.
1 change: 1 addition & 0 deletions changelog.d/canonical-spm-python.breaking.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Require Python 3.11–3.14, matching the supported runtime range of the canonical US model bundle. Install checks now cover that complete range.
1 change: 1 addition & 0 deletions changelog.d/canonical-spm-release-validation.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Require complete authenticated bundle provenance and a registry-only, version-consistent lockfile before automatic release publication.
6 changes: 6 additions & 0 deletions changelog.d/canonical-spm-review.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Preserve native entity ID alignment across input/output tables, reject malformed
group IDs, and retain partial SPM selection semantics through JSON round trips.
Validate managed SPM settings before dataset materialization, preserve
dependency-light bundle bootstrap, and enforce published measurement pins in
the release workflow. Authenticate candidate import sources and correct the
measurement serialization example.
1 change: 1 addition & 0 deletions changelog.d/canonical-spm-wrapper.breaking.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Use the bundle-pinned canonical SPM configuration across US household and population simulations, require explicit geography for SPM-dependent outputs, reject formula-owned SPM inputs, and retain serialisable selection and calculation provenance across results and replay.
1 change: 1 addition & 0 deletions changelog.d/canonical-tuple-pins.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Pin the canonical PolicyEngine tuple: policyengine-us 2.2.1, policyengine-core 3.32.5 and spm-calculator 1.0.0.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Certify the US populace data release `populace-us-2024-spm-20260915` (populace_us_2024, policyengine-us 2.2.1) into the PolicyEngine bundle manifest.
1 change: 1 addition & 0 deletions changelog.d/native-us-hdf-weights.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Load native US pandas HDF datasets that store only calibrated household weights by mapping missing person and entity weights through native membership IDs in memory, preserving source files and supplied weights.
1 change: 1 addition & 0 deletions changelog.d/repository-tro-schema.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Accept the repository-bundle TRACE emission context and validate all generated country TROs against the packaged schema before writing bundle sidecars.
1 change: 1 addition & 0 deletions changelog.d/spm-receipt-comment.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Corrected the SPM receipt storage comment, which justified the H5 dataset by an HDF5 attribute-size limit that the supported h5py range does not have.
1 change: 1 addition & 0 deletions changelog.d/spm-resource-geography-contract.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Documented that SPM geography is required only by results that use the measurement: SPM thresholds and poverty always require it, the ordinary resource outputs never do, and the SPM unit's capped housing subsidy and everything downstream of it require it for units allocated housing assistance.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Regenerated three US household snapshots for two located country changes: the BLS CPI-U actuals refresh that uprates school meal reimbursement rates, and the California standard deduction whose uprating metadata was un-frozen.
1 change: 1 addition & 0 deletions changelog.d/us-model-surface-snapshot.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Regenerated the US model-version surface snapshot for the pinned country and data package.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Regenerated the US single-adult-no-income snapshot for the SNAP ABAWD work-requirement changes, and noted that omitting weekly_hours_worked_before_lsr now reads as zero hours.
1 change: 1 addition & 0 deletions changelog.d/wrapper-repin-policyengine-us-221.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Repin the US bundle, registry lock and TRACE sidecars onto policyengine-us 2.2.1, the build-time model the certified data release records. The certified microdata is byte-identical to the superseded `populace-us-2024-spm-20260909` release.
8 changes: 4 additions & 4 deletions docs/bundles.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,10 @@ Derived artifacts are:
- `src/policyengine/data/bundle/{country}.trace.tro.jsonld`
- GitHub release assets exported from the bundle manifest

The US model in this bundle uses the SPM calculator 0.3.1 API. The manifest pins
`spm-calculator==0.3.1` in the US package scaffold and the generated `us`,
`models`, and `dev` extras. The model formulas and certified dataset artifacts
remain unchanged.
The US model in this bundle uses the SPM calculator 1.0.0 API. The manifest pins
`spm-calculator==1.0.0` as a US runtime dependency, and the generated `us`,
`models` and `dev` extras carry that pin. The model formulas and certified
dataset artifacts remain unchanged.

Previously published versions cannot acquire a new dependency constraint. To
reproduce the historical 5.3.0 US package set, include the compatible calculator
Expand Down
6 changes: 4 additions & 2 deletions docs/countries.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ Override in any output with `income_variable=`.
## State / regional breakdown

US: Populace row scoping uses `state_fips` and `congressional_district_geoid`.
`state_code` remains the human-readable input for custom households.
`state_code` remains the human-readable state input for custom households.
US resource and poverty calculations also require observed `county_fips` or an
explicit national or SPM-area choice; see [Households](households.md#spm-geography-and-measurement-selection).

UK: constituency code and local authority code on every household where available.

Expand Down Expand Up @@ -72,7 +74,7 @@ Most analysis patterns are identical — swap `pe.us` for `pe.uk`:
pe.us.calculate_household(
people=[{"age": 35, "employment_income": 60_000}],
tax_unit={"filing_status": "SINGLE"},
household={"state_code": "CA"},
household={"state_code": "CA", "county_fips": "06037"},
year=2026,
)

Expand Down
Loading