policyengine 6.3.3__tar.gz → 6.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (356) hide show
  1. {policyengine-6.3.3 → policyengine-6.4.0}/CHANGELOG.md +24 -0
  2. {policyengine-6.3.3/src/policyengine.egg-info → policyengine-6.4.0}/PKG-INFO +1 -1
  3. {policyengine-6.3.3 → policyengine-6.4.0}/docs/_quarto.yml +1 -0
  4. {policyengine-6.3.3 → policyengine-6.4.0}/docs/bundles.md +3 -1
  5. policyengine-6.4.0/docs/disclosure.md +239 -0
  6. {policyengine-6.3.3 → policyengine-6.4.0}/docs/engineering/runbooks/build-m-us-populace-certification.md +23 -6
  7. policyengine-6.4.0/docs/engineering/runbooks/us-legacy-spm-sources.md +122 -0
  8. {policyengine-6.3.3 → policyengine-6.4.0}/docs/engineering/skills/data-certification.md +27 -2
  9. {policyengine-6.3.3 → policyengine-6.4.0}/docs/examples.md +7 -0
  10. {policyengine-6.3.3 → policyengine-6.4.0}/docs/microsim.md +18 -0
  11. {policyengine-6.3.3 → policyengine-6.4.0}/docs/outputs.md +28 -1
  12. {policyengine-6.3.3 → policyengine-6.4.0}/docs/regions.md +14 -4
  13. {policyengine-6.3.3 → policyengine-6.4.0}/docs/release-bundles.md +2 -1
  14. policyengine-6.4.0/examples/uk_geography_disclosure.py +84 -0
  15. {policyengine-6.3.3 → policyengine-6.4.0}/examples/us_budgetary_impact.py +12 -3
  16. {policyengine-6.3.3 → policyengine-6.4.0}/pyproject.toml +1 -1
  17. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/core/run_record.py +9 -0
  18. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/core/simulation.py +8 -0
  19. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/data/bundle/manifest.json +12 -12
  20. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/data/bundle/uk.trace.tro.jsonld +5 -5
  21. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/data/bundle/us.trace.tro.jsonld +5 -5
  22. policyengine-6.4.0/src/policyengine/disclosure/__init__.py +65 -0
  23. policyengine-6.4.0/src/policyengine/disclosure/__main__.py +37 -0
  24. policyengine-6.4.0/src/policyengine/disclosure/areas.py +216 -0
  25. policyengine-6.4.0/src/policyengine/disclosure/estimate.py +472 -0
  26. policyengine-6.4.0/src/policyengine/disclosure/noise.py +102 -0
  27. policyengine-6.4.0/src/policyengine/disclosure/release.py +858 -0
  28. policyengine-6.4.0/src/policyengine/disclosure/schema.py +278 -0
  29. policyengine-6.4.0/src/policyengine/disclosure/support.py +166 -0
  30. policyengine-6.4.0/src/policyengine/disclosure/validate.py +211 -0
  31. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/outputs/__init__.py +6 -0
  32. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/outputs/constituency_impact.py +12 -1
  33. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/outputs/local_authority_impact.py +12 -1
  34. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/outputs/poverty.py +21 -1
  35. policyengine-6.4.0/src/policyengine/outputs/uk_geography_disclosure.py +275 -0
  36. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/outputs/uk_geography_impact.py +19 -0
  37. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/tax_benefit_models/common/model_version.py +23 -0
  38. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/tax_benefit_models/uk/model.py +6 -0
  39. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/tax_benefit_models/us/datasets.py +126 -3
  40. policyengine-6.4.0/src/policyengine/tax_benefit_models/us/legacy_spm/__init__.py +120 -0
  41. policyengine-6.4.0/src/policyengine/tax_benefit_models/us/legacy_spm/declarations.py +218 -0
  42. policyengine-6.4.0/src/policyengine/tax_benefit_models/us/legacy_spm/independence.py +121 -0
  43. policyengine-6.4.0/src/policyengine/tax_benefit_models/us/legacy_spm/model_adapter.py +337 -0
  44. policyengine-6.4.0/src/policyengine/tax_benefit_models/us/legacy_spm/record.py +167 -0
  45. policyengine-6.4.0/src/policyengine/tax_benefit_models/us/legacy_spm/registry.py +76 -0
  46. policyengine-6.4.0/src/policyengine/tax_benefit_models/us/legacy_spm/runs.py +140 -0
  47. policyengine-6.4.0/src/policyengine/tax_benefit_models/us/legacy_spm/universe.py +137 -0
  48. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/tax_benefit_models/us/model.py +54 -4
  49. {policyengine-6.3.3 → policyengine-6.4.0/src/policyengine.egg-info}/PKG-INFO +1 -1
  50. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine.egg-info/SOURCES.txt +32 -0
  51. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_constituency_impact.py +29 -0
  52. policyengine-6.4.0/tests/test_disclosure_areas.py +132 -0
  53. policyengine-6.4.0/tests/test_disclosure_estimate.py +558 -0
  54. policyengine-6.4.0/tests/test_disclosure_noise.py +108 -0
  55. policyengine-6.4.0/tests/test_disclosure_release.py +678 -0
  56. policyengine-6.4.0/tests/test_disclosure_schema.py +186 -0
  57. policyengine-6.4.0/tests/test_disclosure_support.py +242 -0
  58. policyengine-6.4.0/tests/test_disclosure_validate.py +217 -0
  59. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_extra_variables.py +3 -0
  60. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_local_authority_impact.py +31 -0
  61. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_poverty_run.py +4 -3
  62. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_release_manifests.py +19 -5
  63. policyengine-6.4.0/tests/test_uk_geography_disclosure.py +277 -0
  64. policyengine-6.4.0/tests/test_us_legacy_spm.py +565 -0
  65. policyengine-6.4.0/tests/test_us_legacy_spm_integration.py +772 -0
  66. policyengine-6.4.0/tests/test_us_legacy_spm_model_contract.py +243 -0
  67. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_us_regions.py +11 -8
  68. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_us_year_file_stamp.py +10 -1
  69. {policyengine-6.3.3 → policyengine-6.4.0}/uv.lock +1 -1
  70. {policyengine-6.3.3 → policyengine-6.4.0}/.claude/policyengine-guide.md +0 -0
  71. {policyengine-6.3.3 → policyengine-6.4.0}/.claude/quick-reference.md +0 -0
  72. {policyengine-6.3.3 → policyengine-6.4.0}/.github/CONTRIBUTING.md +0 -0
  73. {policyengine-6.3.3 → policyengine-6.4.0}/.github/bump_version.py +0 -0
  74. {policyengine-6.3.3 → policyengine-6.4.0}/.github/capture-version.sh +0 -0
  75. {policyengine-6.3.3 → policyengine-6.4.0}/.github/changelog_template.md +0 -0
  76. {policyengine-6.3.3 → policyengine-6.4.0}/.github/check-changelog.sh +0 -0
  77. {policyengine-6.3.3 → policyengine-6.4.0}/.github/copilot-instructions.md +0 -0
  78. {policyengine-6.3.3 → policyengine-6.4.0}/.github/dispatch-policyengine-release.sh +0 -0
  79. {policyengine-6.3.3 → policyengine-6.4.0}/.github/fetch_version.py +0 -0
  80. {policyengine-6.3.3 → policyengine-6.4.0}/.github/get-changelog-diff.sh +0 -0
  81. {policyengine-6.3.3 → policyengine-6.4.0}/.github/has-functional-changes.sh +0 -0
  82. {policyengine-6.3.3 → policyengine-6.4.0}/.github/is-version-number-acceptable.sh +0 -0
  83. {policyengine-6.3.3 → policyengine-6.4.0}/.github/publish-git-tag.sh +0 -0
  84. {policyengine-6.3.3 → policyengine-6.4.0}/.github/wait-for-pypi.sh +0 -0
  85. {policyengine-6.3.3 → policyengine-6.4.0}/.github/workflows/draft-pdf.yml +0 -0
  86. {policyengine-6.3.3 → policyengine-6.4.0}/.github/workflows/pr_code_changes.yaml +0 -0
  87. {policyengine-6.3.3 → policyengine-6.4.0}/.github/workflows/pr_docs_changes.yaml +0 -0
  88. {policyengine-6.3.3 → policyengine-6.4.0}/.github/workflows/push.yaml +0 -0
  89. {policyengine-6.3.3 → policyengine-6.4.0}/.gitignore +0 -0
  90. {policyengine-6.3.3 → policyengine-6.4.0}/.python-version +0 -0
  91. {policyengine-6.3.3 → policyengine-6.4.0}/AGENTS.md +0 -0
  92. {policyengine-6.3.3 → policyengine-6.4.0}/CITATION.cff +0 -0
  93. {policyengine-6.3.3 → policyengine-6.4.0}/CLAUDE.md +0 -0
  94. {policyengine-6.3.3 → policyengine-6.4.0}/CODE_OF_CONDUCT.md +0 -0
  95. {policyengine-6.3.3 → policyengine-6.4.0}/CONTRIBUTING.md +0 -0
  96. {policyengine-6.3.3 → policyengine-6.4.0}/LICENSE +0 -0
  97. {policyengine-6.3.3 → policyengine-6.4.0}/Makefile +0 -0
  98. {policyengine-6.3.3 → policyengine-6.4.0}/README.md +0 -0
  99. {policyengine-6.3.3 → policyengine-6.4.0}/architecture.png +0 -0
  100. {policyengine-6.3.3 → policyengine-6.4.0}/architecture.svg +0 -0
  101. {policyengine-6.3.3 → policyengine-6.4.0}/changelog.d/.gitkeep +0 -0
  102. {policyengine-6.3.3 → policyengine-6.4.0}/docs/.gitignore +0 -0
  103. {policyengine-6.3.3 → policyengine-6.4.0}/docs/_generator/README.md +0 -0
  104. {policyengine-6.3.3 → policyengine-6.4.0}/docs/_generator/build_reference.py +0 -0
  105. {policyengine-6.3.3 → policyengine-6.4.0}/docs/countries.md +0 -0
  106. {policyengine-6.3.3 → policyengine-6.4.0}/docs/data-publishing-design.md +0 -0
  107. {policyengine-6.3.3 → policyengine-6.4.0}/docs/decile-impact-spec.md +0 -0
  108. {policyengine-6.3.3 → policyengine-6.4.0}/docs/dev.md +0 -0
  109. {policyengine-6.3.3 → policyengine-6.4.0}/docs/engineering/runbooks/acs-local-wic-replacement.md +0 -0
  110. {policyengine-6.3.3 → policyengine-6.4.0}/docs/engineering/runbooks/canonical-spm-development.md +0 -0
  111. {policyengine-6.3.3 → policyengine-6.4.0}/docs/engineering/skills/README.md +0 -0
  112. {policyengine-6.3.3 → policyengine-6.4.0}/docs/engineering/skills/github-prs.md +0 -0
  113. {policyengine-6.3.3 → policyengine-6.4.0}/docs/engineering/skills/repository-guidance.md +0 -0
  114. {policyengine-6.3.3 → policyengine-6.4.0}/docs/getting-started.md +0 -0
  115. {policyengine-6.3.3 → policyengine-6.4.0}/docs/households.md +0 -0
  116. {policyengine-6.3.3 → policyengine-6.4.0}/docs/impact-analysis.md +0 -0
  117. {policyengine-6.3.3 → policyengine-6.4.0}/docs/index.md +0 -0
  118. {policyengine-6.3.3 → policyengine-6.4.0}/docs/methodology/index.md +0 -0
  119. {policyengine-6.3.3 → policyengine-6.4.0}/docs/methodology/model-architecture.md +0 -0
  120. {policyengine-6.3.3 → policyengine-6.4.0}/docs/methodology/us-health-costs.md +0 -0
  121. {policyengine-6.3.3 → policyengine-6.4.0}/docs/programs/index.md +0 -0
  122. {policyengine-6.3.3 → policyengine-6.4.0}/docs/programs/us-chip.md +0 -0
  123. {policyengine-6.3.3 → policyengine-6.4.0}/docs/reference/index.md +0 -0
  124. {policyengine-6.3.3 → policyengine-6.4.0}/docs/reforms.md +0 -0
  125. {policyengine-6.3.3 → policyengine-6.4.0}/docs/run-records.md +0 -0
  126. {policyengine-6.3.3 → policyengine-6.4.0}/docs/trace-case-study.md +0 -0
  127. {policyengine-6.3.3 → policyengine-6.4.0}/docs/visualisation.md +0 -0
  128. {policyengine-6.3.3 → policyengine-6.4.0}/examples/belgium_axiom_pilot.py +0 -0
  129. {policyengine-6.3.3 → policyengine-6.4.0}/examples/employment_income_variation_uk.py +0 -0
  130. {policyengine-6.3.3 → policyengine-6.4.0}/examples/employment_income_variation_us.py +0 -0
  131. {policyengine-6.3.3 → policyengine-6.4.0}/examples/household_impact_example.py +0 -0
  132. {policyengine-6.3.3 → policyengine-6.4.0}/examples/income_bands_uk.py +0 -0
  133. {policyengine-6.3.3 → policyengine-6.4.0}/examples/income_distribution_us.py +0 -0
  134. {policyengine-6.3.3 → policyengine-6.4.0}/examples/paper_repro_uk.py +0 -0
  135. {policyengine-6.3.3 → policyengine-6.4.0}/examples/policy_change_uk.py +0 -0
  136. {policyengine-6.3.3 → policyengine-6.4.0}/examples/speedtest_us_simulation.py +0 -0
  137. {policyengine-6.3.3 → policyengine-6.4.0}/paper-preview.html +0 -0
  138. {policyengine-6.3.3 → policyengine-6.4.0}/paper.bib +0 -0
  139. {policyengine-6.3.3 → policyengine-6.4.0}/paper.md +0 -0
  140. {policyengine-6.3.3 → policyengine-6.4.0}/scripts/bundle.py +0 -0
  141. {policyengine-6.3.3 → policyengine-6.4.0}/scripts/certify_data_release.py +0 -0
  142. {policyengine-6.3.3 → policyengine-6.4.0}/scripts/check_data_staleness.py +0 -0
  143. {policyengine-6.3.3 → policyengine-6.4.0}/scripts/check_native_spm_loading.py +0 -0
  144. {policyengine-6.3.3 → policyengine-6.4.0}/scripts/check_release_credentials.py +0 -0
  145. {policyengine-6.3.3 → policyengine-6.4.0}/scripts/export_bundle_release_assets.py +0 -0
  146. {policyengine-6.3.3 → policyengine-6.4.0}/scripts/generate_bundle_artifacts.py +0 -0
  147. {policyengine-6.3.3 → policyengine-6.4.0}/scripts/generate_trace_tros.py +0 -0
  148. {policyengine-6.3.3 → policyengine-6.4.0}/scripts/prepare_package_bundle_update.py +0 -0
  149. {policyengine-6.3.3 → policyengine-6.4.0}/scripts/release_lock.py +0 -0
  150. {policyengine-6.3.3 → policyengine-6.4.0}/scripts/spm_bundle.py +0 -0
  151. {policyengine-6.3.3 → policyengine-6.4.0}/setup.cfg +0 -0
  152. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/__init__.py +0 -0
  153. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/bundle.py +0 -0
  154. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/cli.py +0 -0
  155. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/core/__init__.py +0 -0
  156. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/core/cache.py +0 -0
  157. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/core/dataset.py +0 -0
  158. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/core/dynamic.py +0 -0
  159. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/core/output.py +0 -0
  160. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/core/parameter.py +0 -0
  161. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/core/parameter_node.py +0 -0
  162. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/core/parameter_value.py +0 -0
  163. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/core/policy.py +0 -0
  164. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/core/region.py +0 -0
  165. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/core/scoping_strategy.py +0 -0
  166. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/core/spm.py +0 -0
  167. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/core/tax_benefit_model.py +0 -0
  168. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/core/tax_benefit_model_version.py +0 -0
  169. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/core/variable.py +0 -0
  170. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/countries/__init__.py +0 -0
  171. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/countries/uk/__init__.py +0 -0
  172. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/countries/uk/regions.py +0 -0
  173. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/countries/us/__init__.py +0 -0
  174. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/countries/us/data/__init__.py +0 -0
  175. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/countries/us/data/districts.py +0 -0
  176. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/countries/us/data/places.py +0 -0
  177. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/countries/us/data/states.py +0 -0
  178. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/countries/us/regions.py +0 -0
  179. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/data/__init__.py +0 -0
  180. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/data/schemas/trace_tro.schema.json +0 -0
  181. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/data/uk_geography_assets.py +0 -0
  182. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/derivations/__init__.py +0 -0
  183. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/derivations/narrate.py +0 -0
  184. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/derivations/trace.py +0 -0
  185. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/graph/__init__.py +0 -0
  186. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/graph/extractor.py +0 -0
  187. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/graph/graph.py +0 -0
  188. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/outputs/aggregate.py +0 -0
  189. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/outputs/change_aggregate.py +0 -0
  190. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/outputs/cliff_impact.py +0 -0
  191. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/outputs/congressional_district_impact.py +0 -0
  192. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/outputs/decile_analysis.py +0 -0
  193. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/outputs/decile_grouping.py +0 -0
  194. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/outputs/decile_impact.py +0 -0
  195. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/outputs/extra_variables.py +0 -0
  196. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/outputs/inequality.py +0 -0
  197. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/outputs/intra_decile_impact.py +0 -0
  198. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/outputs/labor_supply_response.py +0 -0
  199. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/outputs/program_statistics.py +0 -0
  200. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/outputs/uk_geography_assets.py +0 -0
  201. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/provenance/__init__.py +0 -0
  202. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/provenance/bundle_validation.py +0 -0
  203. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/provenance/certification.py +0 -0
  204. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/provenance/dataset_materialization.py +0 -0
  205. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/provenance/manifest.py +0 -0
  206. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/provenance/pyproject_pins.py +0 -0
  207. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/provenance/spm_configuration.py +0 -0
  208. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/provenance/trace.py +0 -0
  209. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/provenance/verify.py +0 -0
  210. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/provenance/zenodo.py +0 -0
  211. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/results/__init__.py +0 -0
  212. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/results/schema.py +0 -0
  213. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/results/trace_tro.py +0 -0
  214. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/results/tracking.py +0 -0
  215. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/tax_benefit_models/be/__init__.py +0 -0
  216. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/tax_benefit_models/be/datasets.py +0 -0
  217. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/tax_benefit_models/be/model.py +0 -0
  218. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/tax_benefit_models/common/__init__.py +0 -0
  219. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/tax_benefit_models/common/axes.py +0 -0
  220. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/tax_benefit_models/common/extra_variables.py +0 -0
  221. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/tax_benefit_models/common/household.py +0 -0
  222. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/tax_benefit_models/common/reform.py +0 -0
  223. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/tax_benefit_models/common/result.py +0 -0
  224. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/tax_benefit_models/uk/__init__.py +0 -0
  225. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/tax_benefit_models/uk/analysis.py +0 -0
  226. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/tax_benefit_models/uk/budget_reform_contract.py +0 -0
  227. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/tax_benefit_models/uk/budget_reform_population.py +0 -0
  228. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/tax_benefit_models/uk/datasets.py +0 -0
  229. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/tax_benefit_models/uk/household.py +0 -0
  230. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/tax_benefit_models/us/__init__.py +0 -0
  231. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/tax_benefit_models/us/analysis.py +0 -0
  232. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/tax_benefit_models/us/household.py +0 -0
  233. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/tax_benefit_models/us/legacy_inputs.py +0 -0
  234. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/tax_benefit_models/us/spm.py +0 -0
  235. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/utils/__init__.py +0 -0
  236. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/utils/dates.py +0 -0
  237. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/utils/design.py +0 -0
  238. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/utils/entity_utils.py +0 -0
  239. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/utils/errors.py +0 -0
  240. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/utils/hashing.py +0 -0
  241. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/utils/household_validation.py +0 -0
  242. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/utils/parameter_labels.py +0 -0
  243. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/utils/parametric_reforms.py +0 -0
  244. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine/utils/plotting.py +0 -0
  245. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine.egg-info/dependency_links.txt +0 -0
  246. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine.egg-info/entry_points.txt +0 -0
  247. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine.egg-info/requires.txt +0 -0
  248. {policyengine-6.3.3 → policyengine-6.4.0}/src/policyengine.egg-info/top_level.txt +0 -0
  249. {policyengine-6.3.3 → policyengine-6.4.0}/tests/__init__.py +0 -0
  250. {policyengine-6.3.3 → policyengine-6.4.0}/tests/conftest.py +0 -0
  251. {policyengine-6.3.3 → policyengine-6.4.0}/tests/fixtures/__init__.py +0 -0
  252. {policyengine-6.3.3 → policyengine-6.4.0}/tests/fixtures/filtering_fixtures.py +0 -0
  253. {policyengine-6.3.3 → policyengine-6.4.0}/tests/fixtures/household_calculator_snapshots/uk_couple_two_kids.json +0 -0
  254. {policyengine-6.3.3 → policyengine-6.4.0}/tests/fixtures/household_calculator_snapshots/uk_model_surface.json +0 -0
  255. {policyengine-6.3.3 → policyengine-6.4.0}/tests/fixtures/household_calculator_snapshots/uk_single_adult_employment_income.json +0 -0
  256. {policyengine-6.3.3 → policyengine-6.4.0}/tests/fixtures/household_calculator_snapshots/uk_single_adult_no_income.json +0 -0
  257. {policyengine-6.3.3 → policyengine-6.4.0}/tests/fixtures/household_calculator_snapshots/uk_single_parent_one_child.json +0 -0
  258. {policyengine-6.3.3 → policyengine-6.4.0}/tests/fixtures/household_calculator_snapshots/us_married_two_kids_high_income.json +0 -0
  259. {policyengine-6.3.3 → policyengine-6.4.0}/tests/fixtures/household_calculator_snapshots/us_model_surface.json +0 -0
  260. {policyengine-6.3.3 → policyengine-6.4.0}/tests/fixtures/household_calculator_snapshots/us_single_adult_employment_income.json +0 -0
  261. {policyengine-6.3.3 → policyengine-6.4.0}/tests/fixtures/household_calculator_snapshots/us_single_adult_no_income.json +0 -0
  262. {policyengine-6.3.3 → policyengine-6.4.0}/tests/fixtures/household_calculator_snapshots/us_single_parent_one_child.json +0 -0
  263. {policyengine-6.3.3 → policyengine-6.4.0}/tests/fixtures/parameter_labels_fixtures.py +0 -0
  264. {policyengine-6.3.3 → policyengine-6.4.0}/tests/fixtures/parametric_reforms_fixtures.py +0 -0
  265. {policyengine-6.3.3 → policyengine-6.4.0}/tests/fixtures/poverty_by_demographics_fixtures.py +0 -0
  266. {policyengine-6.3.3 → policyengine-6.4.0}/tests/fixtures/region_fixtures.py +0 -0
  267. {policyengine-6.3.3 → policyengine-6.4.0}/tests/fixtures/release_tros/README.md +0 -0
  268. {policyengine-6.3.3 → policyengine-6.4.0}/tests/fixtures/release_tros/country-models.lock.toml +0 -0
  269. {policyengine-6.3.3 → policyengine-6.4.0}/tests/fixtures/release_tros/manifest.json +0 -0
  270. {policyengine-6.3.3 → policyengine-6.4.0}/tests/fixtures/release_tros/us-release_manifest.json +0 -0
  271. {policyengine-6.3.3 → policyengine-6.4.0}/tests/fixtures/release_tros/us.trace.tro.jsonld +0 -0
  272. {policyengine-6.3.3 → policyengine-6.4.0}/tests/fixtures/spm_development.py +0 -0
  273. {policyengine-6.3.3 → policyengine-6.4.0}/tests/fixtures/us_reform_fixtures.py +0 -0
  274. {policyengine-6.3.3 → policyengine-6.4.0}/tests/fixtures/variable_label_fixtures.py +0 -0
  275. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_aggregate.py +0 -0
  276. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_be_axiom_pilot.py +0 -0
  277. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_budgetary_impact.py +0 -0
  278. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_bump_version.py +0 -0
  279. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_bundle.py +0 -0
  280. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_bundle_metadata.py +0 -0
  281. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_cache.py +0 -0
  282. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_certify_data_release.py +0 -0
  283. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_change_aggregate.py +0 -0
  284. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_cliff_impact.py +0 -0
  285. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_cliff_impact_analysis.py +0 -0
  286. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_congressional_district_impact.py +0 -0
  287. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_dataset_materialization.py +0 -0
  288. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_dataset_persistence.py +0 -0
  289. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_dataset_runtime.py +0 -0
  290. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_dataset_source.py +0 -0
  291. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_decile_grouping.py +0 -0
  292. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_derivations.py +0 -0
  293. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_dict_reforms_on_simulation.py +0 -0
  294. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_entity_mapping.py +0 -0
  295. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_entity_utils.py +0 -0
  296. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_entity_utils_characterization.py +0 -0
  297. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_errors.py +0 -0
  298. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_filtering.py +0 -0
  299. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_generate_trace_tros.py +0 -0
  300. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_graph/__init__.py +0 -0
  301. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_graph/conftest.py +0 -0
  302. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_graph/test_extractor.py +0 -0
  303. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_household_calculator_snapshot.py +0 -0
  304. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_household_impact.py +0 -0
  305. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_inequality.py +0 -0
  306. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_intra_decile_impact.py +0 -0
  307. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_labor_supply_response.py +0 -0
  308. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_manifest_version_mismatch.py +0 -0
  309. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_models.py +0 -0
  310. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_pandas3_compatibility.py +0 -0
  311. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_parameter_labels.py +0 -0
  312. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_parameter_nodes.py +0 -0
  313. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_parameter_values.py +0 -0
  314. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_parametric_reforms.py +0 -0
  315. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_poverty.py +0 -0
  316. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_poverty_by_demographics.py +0 -0
  317. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_preservation_mirror.py +0 -0
  318. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_program_statistics.py +0 -0
  319. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_pyproject_pins.py +0 -0
  320. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_region.py +0 -0
  321. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_region_group_strategy.py +0 -0
  322. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_release_credentials.py +0 -0
  323. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_release_lock.py +0 -0
  324. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_release_tro_generation.py +0 -0
  325. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_results.py +0 -0
  326. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_run_record.py +0 -0
  327. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_scoping_strategy.py +0 -0
  328. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_small_follow_ups.py +0 -0
  329. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_spm_bundle_bootstrap.py +0 -0
  330. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_spm_bundle_tooling.py +0 -0
  331. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_spm_decile.py +0 -0
  332. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_spm_development_authentication.py +0 -0
  333. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_spm_household.py +0 -0
  334. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_spm_model.py +0 -0
  335. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_spm_selection.py +0 -0
  336. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_spm_selection_schema.py +0 -0
  337. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_trace_tro.py +0 -0
  338. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_trace_tro_verify.py +0 -0
  339. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_uk_analysis.py +0 -0
  340. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_uk_budget_reform_contract.py +0 -0
  341. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_uk_dated_reforms.py +0 -0
  342. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_uk_geography_assets.py +0 -0
  343. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_uk_program_statistics.py +0 -0
  344. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_uk_regions.py +0 -0
  345. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_uk_year_file_data_year.py +0 -0
  346. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_us_legacy_inputs.py +0 -0
  347. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_us_legacy_inputs_integration.py +0 -0
  348. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_us_long_term_datasets.py +0 -0
  349. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_us_microsim_structural_reforms.py +0 -0
  350. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_us_native_alignment.py +0 -0
  351. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_us_native_hdf_weights.py +0 -0
  352. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_us_program_statistics.py +0 -0
  353. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_us_reform_application.py +0 -0
  354. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_variable_labels.py +0 -0
  355. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_variable_metadata.py +0 -0
  356. {policyengine-6.3.3 → policyengine-6.4.0}/tests/test_zenodo_mirror.py +0 -0
@@ -1,3 +1,27 @@
1
+ ## [6.4.0] - 2026-10-14
2
+
3
+ ### Added
4
+
5
+ - Added `policyengine.disclosure`, a self-contained layer for statistical disclosure control and uncertainty on area-level outputs, and `compute_uk_geography_disclosure` for UK regions, constituencies and local authorities. Each published number rests on at least 10 distinct survey households (clones counted once through `source_household_id`), carries a 90% bootstrap interval and is rounded to the order of its standard error. Rows are `reported`, `approximate` or `withheld`. A release check reports numbers a reader could recover by subtraction across geography levels, a package and its components, and earlier publications. Keyed noise per survey household is available behind `DisclosureSettings(noise=True)`. `validate_public` and `python -m policyengine.disclosure validate` check the format of published files. UK runs now keep `source_household_id` and `region` on the household output when the dataset provides them.
6
+
7
+ ### Changed
8
+
9
+ - Deprecated `compute_uk_constituency_impacts`, `compute_uk_local_authority_impacts` and their `ConstituencyImpact` and `LocalAuthorityImpact` classes. Their output is not disclosure-controlled; use `compute_uk_geography_disclosure` instead. They now log a warning through the `policyengine` logger and emit a `DeprecationWarning`, and otherwise behave as before.
10
+
11
+
12
+ ## [6.3.4] - 2026-10-13
13
+
14
+ ### Changed
15
+
16
+ - `Poverty.rate` is now `None`, not `0.0`, when nobody in the group is measured (its weighted population with a poverty status is zero), for every source. `headcount` and `total_population` are unchanged, and the poverty DataFrame helpers report the rate as missing. Callers that format or subtract rates must handle `None`.
17
+ - US state and congressional-district regions temporarily filter the certified national dataset again, as in 6.2.1, because the ACS-local release lacks source-backed SPM independence and canonical SPM refused every state-region run (PolicyEngine/microcosm#1263).
18
+
19
+ ### Fixed
20
+
21
+ - Measure SPM poverty on legacy certified US sources that predate SPM measurement-scope declarations, such as the ACS-local Build O release. Following Census's ACS household-population method, ACS group-quarters units are outside the SPM measurement: their SPM results are missing instead of stopping the run with `SPM_COMPOSITION_REQUIRED`, and poverty rates count measured people only. Ordinary tax and benefit results are unchanged.
22
+ - Supply the certified SPM independence role from the national release for the ASEC and PUF records of legacy certified US sources, so independent-teen SPM units are measured instead of stopping SPM calculations.
23
+
24
+
1
25
  ## [6.3.3] - 2026-10-13
2
26
 
3
27
  ### Changed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: policyengine
3
- Version: 6.3.3
3
+ Version: 6.4.0
4
4
  Summary: A package to conduct policy analysis using PolicyEngine tax-benefit models.
5
5
  Author-email: PolicyEngine <hello@policyengine.org>
6
6
  License: GNU AFFERO GENERAL PUBLIC LICENSE
@@ -39,6 +39,7 @@ website:
39
39
  - impact-analysis.md
40
40
  - outputs.md
41
41
  - regions.md
42
+ - disclosure.md
42
43
  - visualisation.md
43
44
  - section: "Methodology"
44
45
  contents:
@@ -147,7 +147,9 @@ python scripts/bundle.py certify-data \
147
147
  --model-version <policyengine-us-version>
148
148
  ```
149
149
 
150
- US state and congressional-district regions scope one certified ACS-local
150
+ **Temporarily**, state and congressional-district regions filter the certified national dataset (`populace_us_2024`), as in policyengine 6.2.1. The certified ACS-local release has no source-backed SPM independence, so canonical SPM refuses thousands of its SPM units (PolicyEngine/microcosm#1263, PolicyEngine/policyengine-sim-api#747). They move back to the ACS-local dataset with a release whose SPM units all have a classified adult.
151
+
152
+ When they use it, US state and congressional-district regions scope one certified ACS-local
151
153
  Populace dataset with row filters. Pass its non-default local-area release
152
154
  manifest through `--regional-manifest-uri`; certification adds the pinned H5
153
155
  artifact to `data_releases.us.datasets` and writes both regional path templates
@@ -0,0 +1,239 @@
1
+ ---
2
+ title: "Disclosure control"
3
+ ---
4
+
5
+ Local results from survey microdata rest on few households, and a licence
6
+ binds every published number. `policyengine.disclosure` turns per-household
7
+ results into area tables that follow the licence's rules and carry their
8
+ uncertainty. Use it for every UK result below the national level that leaves
9
+ your machine.
10
+
11
+ ```python
12
+ from policyengine.outputs import compute_uk_geography_disclosure
13
+
14
+ impact = compute_uk_geography_disclosure(
15
+ baseline_simulation=baseline,
16
+ reform_simulation=reform,
17
+ year=2026,
18
+ levels=("region", "constituency"),
19
+ reform="budget",
20
+ )
21
+ impact.findings # what blocks publication, if anything
22
+ impact.public # the rows that may be published, or None while blocked
23
+ ```
24
+
25
+ The UK datasets derive from surveys under the UK Data Service End User
26
+ Licence. The defaults below follow its disclosure rules. You can raise them
27
+ for a study with stricter conditions; you cannot lower them.
28
+
29
+ ## What a published row holds
30
+
31
+ Each row is one outcome for one area, reform and year.
32
+
33
+ | Column | Content |
34
+ |---|---|
35
+ | `level`, `area_code`, `reform`, `year`, `outcome` | The key of the row |
36
+ | `value`, `lo`, `hi` | The rounded estimate and its 90% interval |
37
+ | `direction` | `gain`, `loss`, `too_close_to_call` or `no_change` |
38
+ | `tier` | `reported`, `approximate` or `withheld` |
39
+ | `reason` | `thin_support` for an approximate row, `disclosure_control` for a withheld row |
40
+ | `support_band` | `<10`, `10–29` or `30+` survey households, never an exact count |
41
+ | `noise` | Whether the row carries keyed noise |
42
+ | `estimator` | `direct`: the estimate comes from the area's own records |
43
+
44
+ The outcomes are `average_change`, `relative_change`, `total_change`,
45
+ `share_gaining`, `share_losing` and `share_no_change`. A withheld row carries
46
+ no value, interval, direction or support band.
47
+
48
+ ## The rules
49
+
50
+ **Count floor.** A number must rest on at least 10 distinct survey households
51
+ that contribute to it. For a change, a household contributes when its income
52
+ changes by more than `change_tolerance` (£1 a year, which is also the lowest
53
+ value the setting takes). Copies and clones of one survey household count
54
+ once, through the dataset's `source_household_id`. For a share, both sides
55
+ must pass: the households that gain and those that do not.
56
+
57
+ **Dominance.** While noise is off, a number is withheld in two cases:
58
+
59
+ - one survey household carries more than half of it, by size;
60
+ - the p% rule: a reader of the number, or one household that knows its own
61
+ part, could estimate some household's part to within 10%. Every household
62
+ is a possible target and every other household a possible reader, so the
63
+ rule also catches a total whose other parts cancel.
64
+
65
+ These rules protect each household against any reader and against any one
66
+ other household. They do not stop two or more households that pool what they
67
+ know: a number that three households carry almost alone passes, as long as 10
68
+ contribute.
69
+
70
+ **Effective sample.** Weights that differ a lot make an estimate less precise
71
+ than its household count suggests. Where the data gives one area and one
72
+ weight per record, a low effective sample makes a row `approximate`: it keeps
73
+ its value and interval, but the interval understates the uncertainty. Where
74
+ the data is an area × household weight matrix, the household count passes by
75
+ construction, so the effective sample must also be at least 10. Weights given
76
+ as a matrix keep this rule whatever they hold: one row of a dense matrix has
77
+ one weight per record, yet every household of the nation sits in that area.
78
+
79
+ **Zero cells.** A cell with no contributing household is published as zero,
80
+ with the interval [0, 0] and the direction `no_change`. It means that no
81
+ surveyed household in the area changed, not that no household there does. Its
82
+ support band counts the households it was measured on.
83
+
84
+ **Settings.** The layer validates its settings again before it uses them, so
85
+ a copy made with `model_copy(update=...)` cannot lower a floor.
86
+
87
+ **Linked outcomes.** Average, relative and total change share a numerator, so
88
+ they are published or withheld together. Gaining, losing and no change add to
89
+ one, so the third share is published only when it is safe to derive.
90
+
91
+ ## Uncertainty and rounding
92
+
93
+ Intervals come from a Poisson bootstrap over survey households with 1,000
94
+ replicates. A ratio resamples its numerator and denominator together. The
95
+ weights stay fixed, so the intervals leave out calibration uncertainty and are
96
+ too narrow, most of all where support is thin.
97
+
98
+ Values are rounded to the order of magnitude of their standard error. The
99
+ interval is rounded outward on the same base.
100
+
101
+ ## The release check
102
+
103
+ Published numbers constrain each other. If a region is public and all but one
104
+ of its constituencies are public, subtraction gives the last one. The check
105
+ looks for such remainders:
106
+
107
+ - child areas against their parent area (constituencies in regions, regions in
108
+ the nation);
109
+ - the components of a package against the package;
110
+ - when two levels that do not nest are released together, an area against
111
+ the areas of the other level that lie wholly inside it, and against the
112
+ areas that meet it (their sum minus the area is what they hold outside it);
113
+ - earlier publications, passed as `prior_public`.
114
+
115
+ A remainder gets the rules of a cell. Estimates added with `publish=False`
116
+ are a reference: the release does not emit their rows, but it treats the rows
117
+ that pass as public elsewhere and the withheld ones as secret, and checks
118
+ them like its own.
119
+
120
+ `compute_uk_geography_disclosure` always checks constituencies and local
121
+ authorities against their region, and regions against the nation, also when
122
+ you publish one level only. A level given as a weight matrix needs
123
+ `parent_of=` with the region of each area; without it the function raises,
124
+ because a check against the nation alone nearly always passes.
125
+
126
+ The check reports; it does not withhold cells by itself. A blocking finding
127
+ names the group and suggests a cell. Withhold it, then check again. When a
128
+ finding suggests no cell, withhold the parent (`finding.group` at
129
+ `finding.group_level`) instead:
130
+
131
+ ```python
132
+ for finding in impact.findings:
133
+ print(finding.code, finding.group, finding.suggested)
134
+
135
+ impact.release.withhold(
136
+ level="constituency",
137
+ area_code="E14001234",
138
+ reform="budget",
139
+ year=2026,
140
+ outcome="average_change",
141
+ )
142
+ impact.refresh() # checks again and fills impact.public once nothing blocks
143
+ ```
144
+
145
+ Two findings can be accepted after review, with `acknowledge=[...]`:
146
+
147
+ - `unchecked_overlap`: levels that overlap without nesting, such as
148
+ constituencies and local authorities, are released together. The release
149
+ checks each area against the areas wholly inside it and against the areas
150
+ that meet it. It does not check other differences between overlapping
151
+ areas, and on weight-matrix data it checks none.
152
+ - `noise_reference_public`: an earlier table shows the same cells under
153
+ another noise setting.
154
+
155
+ ## Noise
156
+
157
+ Noise is off by default. With `DisclosureSettings(noise=True)`, each survey
158
+ household's change is scaled by a fixed factor between 8% and 12% away from 1,
159
+ derived from its id and a secret key. The same household has the same factor
160
+ in every table and every rebuild. Noise replaces the dominance rule; the count
161
+ floor still applies. The range cannot start closer to 1 than 8%.
162
+
163
+ A number that one household dominates, published with noise, gives that
164
+ household's part to within 8 to 12%. The p% rule treats 10% as the line, so
165
+ noise puts such a number right at that line, not safely past it. Whether the
166
+ UK Data Service accepts noise in place of the dominance rule is a licence
167
+ question, which is why noise stays off by default.
168
+
169
+ - **Size.** The noise in a total is about a tenth of that total's sampling
170
+ error.
171
+ - **Key.** Pass `noise_key=` or set `POLICYENGINE_DISCLOSURE_NOISE_KEY`. There
172
+ is no default key. Keep the key out of repositories and CI logs, and do not
173
+ change it between releases of one dataset: two noised versions of a number
174
+ average towards the truth.
175
+ - **Limits.** Denominators carry no noise. The factor cancels in a ratio of
176
+ two numbers that the same household dominates. A remainder that subtraction
177
+ recovers is the noised sum of the withheld cells, so it has the protection
178
+ of a noised cell and no more: the count floor applies to it, and noise
179
+ stands in for the dominance rule as it does for a cell. An un-noised copy
180
+ of the same cell gives the factor away.
181
+
182
+ ## Validating published files
183
+
184
+ `validate_public` checks the format of a table, a CSV file or a directory. It
185
+ needs no key and no microdata, so it can run on every pull request:
186
+
187
+ ```bash
188
+ python -m policyengine.disclosure validate public/data --reviewed notes.csv
189
+ ```
190
+
191
+ It rejects private audit columns, unknown tiers, a value in a withheld row,
192
+ unrounded values, a direction that does not match its interval, and files it
193
+ does not recognise. It cannot tell whether a number rested on enough
194
+ households; only the release that made the file can.
195
+
196
+ ## Private objects
197
+
198
+ `audit_dir=` writes the exact values, household counts and shares behind every
199
+ row. The directory must be outside any git repository.
200
+
201
+ `AreaEstimates`, the object that `estimate_change` returns, holds the same
202
+ exact values. With noise on it also holds the noise factor of every household
203
+ that gains or loses, and within one dataset those factors do the same job as
204
+ the key. Keep it in memory and treat it as you treat the key. It cannot be
205
+ pickled or copied.
206
+
207
+ ## What a reader can still derive
208
+
209
+ `average_change` and `relative_change` together give the area's total
210
+ baseline income to within a few per cent (household count × average ÷
211
+ relative). That total is a denominator: it carries no noise and is not
212
+ checked for dominance.
213
+
214
+ ## Arrays without a simulation
215
+
216
+ The package works on arrays and imports nothing from the rest of the library:
217
+
218
+ ```python
219
+ from policyengine.disclosure import AreaWeights, Release, estimate_change
220
+
221
+ seats = estimate_change(
222
+ level="constituency",
223
+ reform="budget",
224
+ year=2026,
225
+ areas=AreaWeights.from_labels(seat_codes, household_weights),
226
+ source_ids=source_household_ids,
227
+ baseline=baseline_net_income,
228
+ reformed=reformed_net_income,
229
+ )
230
+ release = Release()
231
+ release.add(seats)
232
+ release.check()
233
+ public = release.to_public()
234
+ ```
235
+
236
+ `AreaWeights.from_matrix(matrix, area_codes)` takes an area × household weight
237
+ matrix instead. A dataset without `source_household_id` needs `source_ids=`
238
+ from the caller; the layer does not guess which records share a survey
239
+ household.
@@ -2,8 +2,10 @@
2
2
 
3
3
  Use this runbook to certify a new national US Populace release together with
4
4
  the shared ACS-local release used for state and congressional-district
5
- simulations. Read the [data certification](../skills/data-certification.md)
6
- skill first for validation semantics.
5
+ simulations. For now, state and district simulations use the national release
6
+ instead; see the interim exception in Step 2. Read the
7
+ [data certification](../skills/data-certification.md) skill first for
8
+ validation semantics.
7
9
 
8
10
  This historical filename is retained so existing links remain valid; the
9
11
  procedure itself is release-independent.
@@ -13,7 +15,8 @@ procedure itself is release-independent.
13
15
  Both release manifests have been published to `policyengine/populace-us`, and
14
16
  the model version used by the national release is known. The national release
15
17
  will remain the default dataset; the local-area release will remain
16
- non-default and be selected only for supported regional runs.
18
+ non-default and be selected only for supported regional runs (none while the
19
+ interim exception in Step 2 holds).
17
20
 
18
21
  ## Prerequisites
19
22
 
@@ -60,6 +63,19 @@ This one command:
60
63
  - writes the changelog fragment
61
64
  `changelog.d/certify-us-$NATIONAL_RELEASE_ID.changed.md`.
62
65
 
66
+ **Interim exception (from policyengine 6.3.4; PolicyEngine/policyengine.py#604).**
67
+ State and congressional-district regions filter the national dataset until an
68
+ ACS-local release has no SPM unit without a classified adult
69
+ (PolicyEngine/microcosm#1263). Run the command above unchanged, with
70
+ `--regional-manifest-uri`: without it, certification drops the ACS-local
71
+ dataset and leaves no state or district template. Then, before Step 3, set
72
+ `region_datasets.state` and `region_datasets.congressional_district` in
73
+ `data_releases.us` to `{"path_template": "populace_us_2024.h5"}` by hand. In
74
+ Step 5, expect those two templates to select the national artifact, not the
75
+ local-area one. The data-certification skill
76
+ (`docs/engineering/skills/data-certification.md`) says what must hold before
77
+ the exception ends.
78
+
63
79
  ## Step 3 — regenerate TRACE sidecars
64
80
 
65
81
  The certify step does not touch TRACE sidecars. Regenerate them so they record
@@ -87,15 +103,16 @@ PE_UPDATE_SNAPSHOTS=1 pytest tests/test_household_calculator_snapshot.py
87
103
 
88
104
  ## Step 5 — certify and verify the local-area release
89
105
 
90
- The certification command passes the immutable ACS-local release manifest with
91
- `--regional-manifest-uri`. Confirm all of the following:
106
+ The certification command passes the immutable ACS-local
107
+ release manifest with `--regional-manifest-uri`. Confirm all of the following:
92
108
 
93
109
  - `default_dataset` remains the national Populace dataset;
94
110
  - the local-area artifact appears in `data_releases.us.datasets` with its
95
111
  repository type, immutable revision, and SHA-256;
96
112
  - `region_datasets.national` selects the national artifact;
97
113
  - `region_datasets.state` and `region_datasets.congressional_district` select
98
- the shared local-area artifact;
114
+ the shared local-area artifact (the national artifact while the interim
115
+ exception in Step 2 holds);
99
116
  - no derived `states/*.h5` or `districts/*.h5` artifacts are runtime inputs.
100
117
 
101
118
  ```bash
@@ -0,0 +1,122 @@
1
+ # Legacy US SPM sources (backward compatibility)
2
+
3
+ > **Backward compatibility, not a data contract.** This layer exists so that
4
+ > certified US sources published *before* SPM declarations existed can still
5
+ > be measured. New certified sources must carry the declarations themselves;
6
+ > do not register them here.
7
+
8
+ policyengine-us measures SPM poverty only when a source declares two things:
9
+
10
+ - **Measurement scope:** which SPM units are inside the SPM measurement
11
+ population (`spm_unit_spm_universe_status`: `INCLUDED`/`OUTSIDE`, the
12
+ contract of PolicyEngine/microcosm#977).
13
+ - **Independence role:** which 15–17-year-olds independently head their own
14
+ SPM unit (`is_spm_independent_minor_role`).
15
+
16
+ A legacy source carries neither. Every SPM calculation on it stops with
17
+ `SPM_COMPOSITION_REQUIRED` ("SPM unit has no classified adult").
18
+
19
+ The package
20
+ [`policyengine.tax_benefit_models.us.legacy_spm`](../../../src/policyengine/tax_benefit_models/us/legacy_spm/__init__.py)
21
+ derives the missing declarations from evidence a legacy source does carry.
22
+ Nobody is dropped: memberships, weights and every ordinary tax, benefit and
23
+ income calculation are unchanged.
24
+
25
+ ## Registered sources
26
+
27
+ Sources are keyed by certified SHA-256 in `legacy_spm/registry.py`.
28
+
29
+ | Source | Scope rule | Independence list |
30
+ | --- | --- | --- |
31
+ | `populace_us_2024_acs_local` Build O (`769756c3…a7ec`) | `acs_household_population` | national release `source_spm_person_independence.csv` (`22b5968d…3ce5`) |
32
+
33
+ ### Scope rule `acs_household_population` (#597)
34
+
35
+ Census's ACS SPM methodology measures the household population only.
36
+
37
+ - ACS records with `TYPEHUGQ` 2 or 3 and the matching `RELSHIPP` (37 or 38) are
38
+ group quarters, so their SPM units are `OUTSIDE`.
39
+ - ACS housing-unit records are `INCLUDED`.
40
+ - Records from the `asec` and `puf_tax_detail` channels are `INCLUDED`.
41
+
42
+ Age is never used. Unknown channels, missing or inconsistent evidence, and SPM
43
+ units that mix group quarters with household people all raise.
44
+
45
+ On the full Build O source, 183,206 SPM units are outside the measurement.
46
+
47
+ ### Independence list (#598)
48
+
49
+ The source's ASEC/PUF records are the same records the certified national
50
+ release carries with a source-backed independence role. The list is joined by
51
+ `person_id` and `person_spm_unit_id`, and the join must be exact:
52
+
53
+ - every ASEC/PUF person appears once, in the same SPM unit;
54
+ - the list names nobody else.
55
+
56
+ ACS people keep the model's own fallback (household head or spouse).
57
+
58
+ On Build O, exactly 28 units change: Census-built units around an independent
59
+ teen.
60
+
61
+ ## How runs get the declarations
62
+
63
+ | Path | What happens |
64
+ | --- | --- |
65
+ | `create_datasets` / `ensure_datasets` | Year files store the declarations as ordinary input columns, with a `policyengine_legacy_spm_declarations` record. |
66
+ | `Simulation.run()` over a raw legacy source file | The declarations are derived in memory. The file is recognised by its evidence columns and then its SHA-256, which is hashed once per process. |
67
+ | `managed_microsimulation` | The declarations are derived from the loaded tables and set on the simulation and its branches. |
68
+
69
+ `legacy_spm.model_adapter` then makes the model honour the scope:
70
+
71
+ - **native:** policyengine-us defines `spm_unit_spm_universe_status`
72
+ (PolicyEngine/policyengine-us#9462). The declaration is just an input, and
73
+ nothing is overridden.
74
+ - **override:** policyengine-us 2.2.1 cannot read it. A variable-only reform:
75
+ - adds the input;
76
+ - wraps the installed SPM chain so that outside units never reach the
77
+ canonical provider and every SPM outcome for them is NaN ("not measured").
78
+
79
+ Poverty indicators become floats (1.0, 0.0 or NaN). The override wraps the
80
+ installed formulas, with one exception: `spm_unit_income_decile` ranks
81
+ units, so it is recalculated over measured units with the installed method.
82
+ A contract test pins that method. The override refuses to run if the SPM
83
+ chain no longer has the verified shape.
84
+
85
+ Poverty rates count measured people only. A group with nobody measured has a
86
+ rate of `None`, not 0.
87
+
88
+ ## Staleness
89
+
90
+ The record holds a `LegacySPMProfile`: the registry entry plus
91
+ `ADAPTER_REVISION`. Checks are total and exact, like the year-file stamp:
92
+
93
+ - `ensure_datasets` cuts a year file again, and `load_datasets` refuses it, when
94
+ its record is absent, unreadable, malformed, or from another profile.
95
+ - `Simulation.load()` refuses an output saved under a different profile.
96
+
97
+ Raise `ADAPTER_REVISION` whenever a change to derivation or the override means
98
+ existing files must be made again.
99
+
100
+ ## When the model or data changes
101
+
102
+ - **policyengine-us gains native scope (#9462).**
103
+ `test_the_installed_model_does_not_read_scope_natively_yet` fails. Check that
104
+ the native members include `INCLUDED` and `OUTSIDE`, and confirm the native
105
+ runs in the integration tests. Then delete the override half of
106
+ `model_adapter` (keep the derivation) and raise `ADAPTER_REVISION`.
107
+ - **The SPM chain changes.** `test_the_override_covers_every_variable_that_depends_on_the_provider`,
108
+ `test_the_installed_chain_has_the_verified_shape` or
109
+ `test_the_recalculated_decile_matches_the_installed_method` fails. Re-verify
110
+ the override against the new chain before bumping the pin.
111
+ - **A rebuilt source declares scope and role itself.** Point the bundle at it.
112
+ Keep the Build O registry entry only while anything still reads Build O,
113
+ then delete it.
114
+
115
+ ## Related
116
+
117
+ - Microcosm #977: scope classification at source.
118
+ - Microcosm #959: independence role in US builds.
119
+ - policyengine-us #9462: native scope.
120
+ - policyengine.py #519: nullable SPM summaries.
121
+ - The year-file and output stamps (#590, and #593/#594 in flight). Fold this
122
+ record into them once those land.
@@ -35,8 +35,33 @@ python scripts/bundle.py certify-data --country us --data-producer populace \
35
35
  --model-version "<policyengine-us-version>"
36
36
  ```
37
37
 
38
- US state and congressional-district regions are row filters over one shared,
39
- certified ACS-local Populace dataset. Its release manifest must declare
38
+ **Interim exception (from policyengine 6.3.4; PolicyEngine/policyengine.py#604).**
39
+ State and congressional-district regions currently filter the certified
40
+ national dataset, not the ACS-local one. The certified ACS-local release has
41
+ no source-backed SPM independence, so canonical SPM refuses its SPM units that
42
+ have no classified adult, and with them every state-region run
43
+ (PolicyEngine/microcosm#1263, PolicyEngine/policyengine-sim-api#747). The 6.3.4
44
+ manifest was certified with `--regional-manifest-uri`, as below, and then
45
+ edited by hand. Until the exception ends, do the same:
46
+
47
+ - still pass `--regional-manifest-uri`. Without it, certification rewrites
48
+ `data_releases.us` from the national manifest alone, which drops the
49
+ ACS-local dataset and leaves no state or district template at all;
50
+ - then set `region_datasets.state` and `region_datasets.congressional_district`
51
+ to `{"path_template": "populace_us_2024.h5"}` by hand, before regenerating
52
+ the TRACE sidecars. `tests/test_release_manifests.py` fails if they name
53
+ the ACS-local file, and also if the ACS-local dataset is no longer
54
+ certified.
55
+
56
+ Restore the ACS-local regions only with an ACS-local release in which every
57
+ SPM unit has at least one classified adult under the pinned spm-calculator's
58
+ rule (zero unclassified units), and after a state-region run through the
59
+ public wrapper succeeds on it. Then remove this exception, the temporary test
60
+ and the matching notes in `docs/regions.md` and `docs/bundles.md`.
61
+
62
+ Outside that exception, US state and congressional-district regions are row
63
+ filters over one shared, certified ACS-local Populace dataset. Its release
64
+ manifest must declare
40
65
  `dataset_role: non_default_local_area`, `is_default: false`, no default
41
66
  datasets, and exactly one pinned H5 microdata artifact. Certification writes:
42
67
 
@@ -16,6 +16,13 @@ Applying parametric reforms, comparing baseline and reform with `ChangeAggregate
16
16
  ```{.python include="../examples/policy_change_uk.py"}
17
17
  ```
18
18
 
19
+ ## UK geography results under disclosure control
20
+
21
+ Estimating results by area from per-household arrays, checking the release, withholding a cell and validating the public table. The data is synthetic.
22
+
23
+ ```{.python include="../examples/uk_geography_disclosure.py"}
24
+ ```
25
+
19
26
  ## UK income bands
20
27
 
21
28
  Calculating net income and tax by income decile using representative microdata and `Aggregate` with quantile filters.
@@ -87,6 +87,24 @@ before passing them to the country model. Generic adult/child counts remain
87
87
  separate. The native source enrichment is not recalibration, and inherited
88
88
  schema-5 calibration diagnostics cannot be relabeled as schema 6.
89
89
 
90
+ **Legacy SPM sources (backward compatibility).** Some certified US sources
91
+ predate SPM declarations, for example the ACS-local Build O release. For those
92
+ sources, .py derives the declarations from evidence they carry, following
93
+ Census's ACS SPM methodology, which measures the household population only:
94
+
95
+ - ACS group-quarters SPM units are outside the SPM measurement. Their SPM
96
+ thresholds, resources and poverty indicators are missing (NaN).
97
+ - Poverty indicators on those sources are floats: 1.0, 0.0, or NaN for "not
98
+ measured".
99
+ - Poverty rates count measured people only. A group with nobody measured has
100
+ a rate of `None`, not 0.
101
+ - The sources' ASEC and PUF records take the certified SPM independence role
102
+ from the national release.
103
+
104
+ Ordinary tax, benefit and income results are unchanged. Outputs record the
105
+ declarations they used under `legacy_spm_declarations`. See
106
+ [the runbook](engineering/runbooks/us-legacy-spm-sources.md).
107
+
90
108
  The wrapper's native pandas HDF loader accepts files that store only calibrated
91
109
  `household_weight`. It maps missing person and group weight columns through
92
110
  native membership IDs in memory, retaining supplied weight columns and the
@@ -167,6 +167,12 @@ rate.run()
167
167
  rate.headcount, rate.total_population, rate.rate
168
168
  ```
169
169
 
170
+ `rate.rate` is `None` when nobody in the group is measured: the group's
171
+ weighted population with a poverty status is zero, for example a filter that
172
+ matches no one, or a group whose members are all outside the SPM measurement
173
+ on a legacy source. That is not a measured rate of zero, so handle `None`
174
+ before formatting or subtracting rates.
175
+
170
176
  For all canonical poverty measures over one simulation:
171
177
 
172
178
  ```python
@@ -260,7 +266,28 @@ for row in impacts.district_results:
260
266
  print(row["district_geoid"], row["avg_change"], row["winner_percentage"])
261
267
  ```
262
268
 
263
- ### UK constituencies / local authorities
269
+ ### UK regions, constituencies and local authorities
270
+
271
+ `compute_uk_geography_disclosure` returns results by area under disclosure
272
+ control: each number passes a floor on the survey households behind it and
273
+ carries a 90% interval. Use it for anything you publish. See
274
+ [Disclosure control](disclosure.md).
275
+
276
+ ```python
277
+ from policyengine.outputs import compute_uk_geography_disclosure
278
+
279
+ impact = compute_uk_geography_disclosure(
280
+ baseline_simulation=baseline,
281
+ reform_simulation=reform,
282
+ year=2026,
283
+ levels=("region", "constituency"),
284
+ )
285
+ impact.public.to_frame()
286
+ ```
287
+
288
+ The two older functions below are deprecated. Their output is not
289
+ disclosure-controlled, so do not publish it when the data is licensed survey
290
+ microdata.
264
291
 
265
292
  Constituency and local-authority breakdowns group household output rows by
266
293
  dataset-provided longwise geography columns. Constituencies use
@@ -23,9 +23,13 @@ ca_snap = Aggregate(
23
23
  ca_snap.run()
24
24
  ```
25
25
 
26
- Each state is a region in the US registry. State regions load the ACS-local
27
- Populace dataset declared by `region.dataset_path`, then scope its rows by
28
- `state_fips`. They do not require separate state H5 files:
26
+ Each state is a region in the US registry. State regions load the Populace
27
+ dataset declared by `region.dataset_path`, then scope its rows by `state_fips`.
28
+ They do not require separate state H5 files.
29
+
30
+ **Temporarily**, state and congressional-district regions filter the certified national dataset (`populace_us_2024`), as in policyengine 6.2.1. The certified ACS-local release has no source-backed SPM independence, so canonical SPM refuses thousands of its SPM units (PolicyEngine/microcosm#1263, PolicyEngine/policyengine-sim-api#747). They move back to the ACS-local dataset with a release whose SPM units all have a classified adult.
31
+
32
+ For example:
29
33
 
30
34
  ```python
31
35
  states = pe.us.model.region_registry.get_by_type("state")
@@ -52,7 +56,8 @@ for row in impacts.district_results:
52
56
 
53
57
  `district_geoid` is the SSDD integer (state FIPS × 100 + district number;
54
58
  at-large districts use `00`). Congressional district regions load the same
55
- ACS-local file and scope its rows by `congressional_district_geoid`.
59
+ file as state regions (for now the national dataset; see above) and scope its rows by
60
+ `congressional_district_geoid`.
56
61
 
57
62
  ## UK countries
58
63
 
@@ -88,6 +93,11 @@ national UK dataset.
88
93
 
89
94
  ## UK parliamentary constituencies
90
95
 
96
+ To publish results by constituency, local authority or region, use
97
+ `compute_uk_geography_disclosure`; see [Disclosure control](disclosure.md).
98
+ The functions in this section and the next are deprecated: their output is
99
+ not disclosure-controlled.
100
+
91
101
  Constituency-level impacts group household output rows by the longwise
92
102
  `constituency_code_oa` column carried by the dataset. If the constituency CSV is
93
103
  available locally or from the PolicyEngine UK GCS bucket, PolicyEngine uses it
@@ -207,7 +207,8 @@ python scripts/bundle.py certify-data --country us --data-producer populace \
207
207
 
208
208
  That produces one US bundle manifest entry containing the Populace national
209
209
  default dataset and the certified ACS-local regional dataset. State and
210
- congressional-district simulations use the latter with runtime row filters, so
210
+ congressional-district simulations use one of them with runtime row filters (for now the
211
+ national dataset; see [Regions](regions.md)), so
211
212
  derived `states/*.h5` or `districts/*.h5` files are not vendored into
212
213
  `data_releases.us.datasets`.
213
214