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
4 changes: 2 additions & 2 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ from branches in `PolicyEngine/policyengine.py`; never create fork PRs.
For repository-wide API, testing, documentation, release, or package-boundary
changes, read `docs/engineering/skills/repository-guidance.md`.

For certified release-bundle updates or reviews, read
`docs/engineering/skills/release-bundles.md`.
For data-release certification or reviews, read
`docs/engineering/skills/data-certification.md`.
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ Before making or reviewing repository-wide API, testing, documentation, release,
or package-boundary changes, read
`docs/engineering/skills/repository-guidance.md`.

Before updating or reviewing certified release bundles, read
`docs/engineering/skills/release-bundles.md`.
Before certifying or reviewing a country data release, read
`docs/engineering/skills/data-certification.md`.

## Repository Boundaries

Expand Down
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@ Before making or reviewing repository-wide API, testing, documentation, release,
or package-boundary changes, read
`docs/engineering/skills/repository-guidance.md`.

Before updating or reviewing certified release bundles, read
`docs/engineering/skills/release-bundles.md`.
Before certifying or reviewing a country data release, read
`docs/engineering/skills/data-certification.md`.
1 change: 1 addition & 0 deletions changelog.d/migrate-off-bundles.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Certify country data releases directly from their Hugging Face release manifests (`scripts/certify_data_release.py`), replacing the policyengine-bundles import flow. The vendored US manifest is regenerated through the new path (byte-identical apart from the certification source strings), and the vendored bundle archive copies are no longer shipped.
4 changes: 2 additions & 2 deletions docs/engineering/skills/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ Current skills:
changelog-fragment requirements, PR head verification, and title conventions.
- `repository-guidance.md`: policyengine.py structure, commands, package
boundaries, test expectations, and repo-specific anti-patterns.
- `release-bundles.md`: certified release-bundle refresh workflow, model/data
compatibility gates, expected files, and bundle-specific tests.
- `data-certification.md`: certifying country data releases from their
release manifests, validation semantics, expected files, and legacy paths.
83 changes: 83 additions & 0 deletions docs/engineering/skills/data-certification.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Data certification

Use this skill when certifying a country data release for `policyengine.py`,
or reviewing a certification change.

## What certification is

A data release is published on Hugging Face with a release manifest: per-
artifact repo/revision/sha256 pins, build provenance, compatibility claims,
and region dataset templates. Certification asserts that *this*
`policyengine.py` release, with the model package pinned in
`pyproject.toml`, serves that data release — and the assertion is only made
good by the test suite passing on the exact pinned pair.

There is no intermediate bundle repo. The vendored country manifest at
`src/policyengine/data/release_manifests/{country}.json` is derived directly
from the data release manifest.

## Certifying a release

Open the work on a fresh branch from current `main` (use a clean worktree if
the checkout is dirty).

```bash
python scripts/certify_data_release.py --country us \
--manifest-uri "hf://dataset/policyengine/populace-us@<tag>/releases/<tag>/release_manifest.json"
```

The script fetches and validates the manifest (every artifact must carry a
revision pin; the certified dataset must be reachable), writes the vendored
country manifest, exact-pins the country model package and raises the core
floor in `pyproject.toml`, regenerates the TRACE TRO sidecar, and writes a
Towncrier changelog fragment.

Private data (UK) requires `HUGGING_FACE_TOKEN` or `HF_TOKEN`.

After running:

- `uv lock` if pins moved, then `uv sync --all-extras`,
- run the full test suite — snapshot drift from a model bump is refreshed
with `PE_UPDATE_SNAPSHOTS=1 pytest tests/test_household_calculator_snapshot.py`,
- commit the manifest, TRO, `pyproject.toml`, `uv.lock`, and fragment
together.

A certification PR should normally change only:

- `src/policyengine/data/release_manifests/{country}.json` (+ `.trace.tro.jsonld`)
- `pyproject.toml` / `uv.lock`
- one Towncrier fragment under `changelog.d/`
- test constants/snapshots that pin certified versions

## Validation semantics

Hard failures (certification refuses): missing national default dataset,
default dataset absent from artifacts, any artifact without a revision pin,
unreachable certified dataset, unknown country.

Certification gate: the model version must either exactly match the
build-time model (`compatibility_basis: built_with_model_package`) or be
covered by the publisher's `compatible_model_packages` claim
(`compatibility_basis: compatible_model_packages`, recorded with a
warning — the publisher's claim is made good only by this repo's test
suite passing on the pinned pair). Neither basis means certification is
refused: a new data build or a published compatibility claim is required.

Warnings (recorded, not blocking): artifacts without sha256, and the
publisher-claim basis above.

## Legacy paths

Countries whose current data release predates release manifests (the UK
enhanced FRS) are refreshed with the legacy single-country tool until their
next release certifies through a manifest:

```bash
python scripts/refresh_release_bundle.py --country uk --model-version 2.89.0
```

Do not hand-edit vendored country manifests for normal updates.

The retired `policyengine-bundles` flow (candidates → generated bundle →
archive import) is preserved read-only in that repo's history; bundles
4.15.x–4.16.x remain the historical record of earlier certifications.
122 changes: 0 additions & 122 deletions docs/engineering/skills/release-bundles.md

This file was deleted.

40 changes: 28 additions & 12 deletions docs/release-bundles.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Release Bundles

> **Current process.** Certification now runs inside this repository:
> `scripts/certify_data_release.py` derives the vendored country manifest
> directly from a country's data release manifest (see the
> [data certification](engineering/skills/data-certification.md)
> engineering skill). The intermediate `policyengine-bundles` repository
> flow is retired; its published bundles remain the historical record of
> earlier certifications. The architecture below — country `*-data`
> repos publish immutable manifests, `policyengine.py` certifies — is
> unchanged.

This document defines the intended reproducibility boundary for `policyengine.py`.

The key design decision is:
Expand Down Expand Up @@ -59,18 +69,19 @@ It does not define the final supported runtime bundle exposed to users.

It does not rebuild microdata artifacts.

New multi-country bundles are generated and archived in
`PolicyEngine/policyengine-bundles`. `policyengine.py` vendors one current
bundle from that archive under `src/policyengine/data/bundle/`, then generates
the legacy country release manifests that runtime code still reads. The import
Certification runs in this repository: the vendored country release
manifest under `src/policyengine/data/release_manifests/` is derived
directly from the country's published data release manifest. The
entrypoint is:

```bash
python scripts/import_policyengine_bundle.py 4.14.0
python scripts/certify_data_release.py --country us \
--manifest-uri "hf://dataset/policyengine/populace-us@<tag>/releases/<tag>/release_manifest.json"
```

The `policyengine-bundles` publish workflow runs this importer automatically
when it opens the consuming `.py` PR.
Earlier releases (policyengine 4.15.x–4.16.x) were certified through the
`PolicyEngine/policyengine-bundles` archive flow; those bundles remain the
historical record of their certifications.

## Two manifest layers

Expand Down Expand Up @@ -396,11 +407,16 @@ Things that should usually not affect the fingerprint:
`policyengine.py` may certify a staged data artifact for a model version only if one of the following is true:

1. the model version exactly matches the `built_with_model_package.version`
2. the model version has the same `data_build_fingerprint` as the build-time model version

If neither is true, the bundle release must fail and a new data build is required.

This should be a hard failure, not a warning.
(`compatibility_basis: built_with_model_package`)
2. the data publisher's `compatible_model_packages` covers the model version
(`compatibility_basis: compatible_model_packages` — the publisher's claim,
recorded with a warning and made good by the test suite passing on the
pinned pair)

If neither is true, certification fails hard and a new data build or a
published compatibility claim is required. A `data_build_fingerprint`
basis (same fingerprint as the build-time model) is a planned third
basis; it requires fingerprint metadata from the installed model package.

## Artifact states

Expand Down
Loading
Loading