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: 1 addition & 3 deletions .github/workflows/push.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,8 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: 18.x
- name: Install MyST
run: npm install -g mystmd
- name: Build HTML Assets
run: cd docs && myst build --html
run: make docs
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
Expand Down
12 changes: 9 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
.PHONY: docs
.PHONY: docs docs-serve

MYSTMD_VERSION ?= 1.8.3
MYST_CMD = npx --yes mystmd@$(MYSTMD_VERSION)

all: build-package

docs:
cd docs && jupyter book start
cd docs && $(MYST_CMD) build --html

docs-serve:
cd docs && $(MYST_CMD) start

install:
uv pip install -e .[dev]
Expand All @@ -27,4 +33,4 @@ build-package:
python -m build

test:
pytest tests --cov=policyengine --cov-report=term-missing
pytest tests --cov=policyengine --cov-report=term-missing
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ uv pip install -e .[dev] # install with dev dependencies (pytest, ruff, m
```bash
make format # ruff format
make test # pytest with coverage
make docs # build Jupyter Book documentation
make docs # build static MyST/Jupyter Book 2 HTML docs
make docs-serve # preview the docs locally
make clean # remove caches, build artifacts, .h5 files
```

Expand Down
1 change: 1 addition & 0 deletions changelog.d/codex-trace-tro-export.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add TRACE TRO export helpers for certified runtime bundles and expose them through `policyengine.core`.
3 changes: 2 additions & 1 deletion docs/dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ dependencies used in CI (pytest, ruff, mypy, towncrier).
```bash
make format # ruff format
make test # pytest with coverage
make docs # run the MyST docs build used in CI via npx
make docs # build static MyST/Jupyter Book 2 HTML docs
make docs-serve # preview the docs locally
make clean # remove caches, build artifacts, .h5 files
```

Expand Down
49 changes: 49 additions & 0 deletions docs/release-bundles.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,55 @@ Notes:
- apps and APIs should surface this bundle, not only country package versions
- a bundle may reuse a previously staged data artifact if compatibility is explicitly certified

## TRACE export

The internal build manifest and certified runtime bundle remain the operational source of
truth.

TRACE sits on top of those manifests as a standards-based export layer.

### What gets exported

Country `*-data` repos should emit a `trace.tro.jsonld` file for each published data
release. That TRO should cover:

- the release manifest itself
- each published artifact hash listed in the release manifest
- the build-time model provenance recorded in the release manifest

`policyengine.py` should emit a separate certified-bundle TRO. That TRO should cover:

- the bundled country release manifest shipped in `policyengine.py`
- the country data release manifest resolved for the certified data package version
- the certified dataset artifact hash
- the certification basis used to allow runtime reuse

### What TRACE does not replace

TRACE is not the source of truth for compatibility policy.

In particular, TRACE does not decide:

- whether a new model version can safely reuse an existing data artifact
- how `data_build_fingerprint` is computed
- which staged artifact becomes a supported runtime default

Those decisions still belong to the country data build manifest and the
`policyengine.py` certified runtime bundle.

### Why we still want it

TRACE adds three things our internal manifests do not provide by themselves:

- a standard declaration format for provenance exchange
- a composition fingerprint over the exact artifacts in scope
- a better external surface for papers, audits, and reproducibility reviews

That is why the recommended design is:

- internal manifests for build/certification control
- generated TRACE TROs for standards-based export

## Compatibility rule

The architecture should avoid forcing a new data build for every harmless country model release.
Expand Down
7 changes: 7 additions & 0 deletions src/policyengine/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@
from .tax_benefit_model_version import (
TaxBenefitModelVersion as TaxBenefitModelVersion,
)
from .trace_tro import (
build_trace_tro_from_release_bundle as build_trace_tro_from_release_bundle,
)
from .trace_tro import (
compute_trace_composition_fingerprint as compute_trace_composition_fingerprint,
)
from .trace_tro import serialize_trace_tro as serialize_trace_tro
from .variable import Variable as Variable

# Rebuild models to resolve forward references
Expand Down
24 changes: 23 additions & 1 deletion src/policyengine/core/tax_benefit_model_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,14 @@

from pydantic import BaseModel, Field

from .release_manifest import CountryReleaseManifest, DataCertification, PackageVersion
from .release_manifest import (
CountryReleaseManifest,
DataCertification,
PackageVersion,
get_data_release_manifest,
)
from .tax_benefit_model import TaxBenefitModel
from .trace_tro import build_trace_tro_from_release_bundle

if TYPE_CHECKING:
from .parameter import Parameter
Expand Down Expand Up @@ -201,6 +207,22 @@ def release_bundle(self) -> dict[str, str | None]:
),
}

@property
def trace_tro(self) -> dict:
if self.release_manifest is None:
raise ValueError(
"TRACE TRO export requires a bundled country release manifest."
)

data_release_manifest = get_data_release_manifest(
self.release_manifest.country_id
)
return build_trace_tro_from_release_bundle(
self.release_manifest,
data_release_manifest,
certification=self.data_certification,
)

def __repr__(self) -> str:
# Give the id and version, and the number of variables, parameters, parameter nodes, parameter values
return f"<TaxBenefitModelVersion id={self.id} variables={len(self.variables)} parameters={len(self.parameters)} parameter_nodes={len(self.parameter_nodes)} parameter_values={len(self.parameter_values)}>"
Loading
Loading