From 895914f5d1c82731a136ceab9e80bc4007de7b24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20Juaristi?= <127882282+juaristi22@users.noreply.github.com> Date: Mon, 17 Aug 2026 17:52:30 +0200 Subject: [PATCH 01/10] Adopt the UK national calibration contract as a Microcosm resource chronicle#166 ruling (2026-08-13): selection contracts live in the consumer; Chronicle is a facts-only layer. This re-homes the uk_national contract from chronicle PR #164 (held in draft for the ruling) into uk/uk_national_targets.json, following the US pattern - an untyped, value-free resource the runtime interprets (fiscal_target_references precedent), registered in the country package. The contract carries the 186 value-free target declarations verbatim (ledger_selector with dimension-value pins, measurement contracts, policyengine bindings including the declarative counterfactual kinds, per-target assertion policies) plus the full uk-data registry parity accounting: 651 rows at pinned ref ebf733c = 609 mapped + 42 signed exclusions. Values resolve only from a hash-pinned Chronicle consumer artifact at build time; compilation to TargetSpec rows, the UK mapping module, and the counterfactual metric providers are microcosm#622, and the calibration seam is microcosm#623. Tests pin the guarantees the chronicle profile loader used to enforce: value-free and hook-free at every depth (filter-predicate carve-out), closed-world binding kinds, selectors on every target, projection families carrying allow_source_projection, unique metric names, and the registry accounting closing exactly. Co-Authored-By: Claude Fable 5 --- .../microcosm/build/uk/country_package.json | 3 +- .../build/uk/uk_national_targets.json | 9827 +++++++++++++++++ .../tests/test_country_spec.py | 1 + .../tests/test_uk_national_targets.py | 128 + 4 files changed, 9958 insertions(+), 1 deletion(-) create mode 100644 packages/microcosm-build/src/microcosm/build/uk/uk_national_targets.json create mode 100644 packages/microcosm-build/tests/test_uk_national_targets.py diff --git a/packages/microcosm-build/src/microcosm/build/uk/country_package.json b/packages/microcosm-build/src/microcosm/build/uk/country_package.json index d5e83e02b..d0bb6ae16 100644 --- a/packages/microcosm-build/src/microcosm/build/uk/country_package.json +++ b/packages/microcosm-build/src/microcosm/build/uk/country_package.json @@ -20,6 +20,7 @@ "qrf_tail_reviewed_exclusions.json", "release_input_coverage_manifest.json", "was_wealth_support_bounds.json", - "uk_local_target_census.json" + "uk_local_target_census.json", + "uk_national_targets.json" ] } diff --git a/packages/microcosm-build/src/microcosm/build/uk/uk_national_targets.json b/packages/microcosm-build/src/microcosm/build/uk/uk_national_targets.json new file mode 100644 index 000000000..6ed2e332f --- /dev/null +++ b/packages/microcosm-build/src/microcosm/build/uk/uk_national_targets.json @@ -0,0 +1,9827 @@ +{ + "schema_version": 1, + "country": "uk", + "description": "UK national calibration contract: value-free target declarations over Chronicle facts. Selection contracts live in Microcosm per the chronicle#166 ruling (2026-08-13): Chronicle is a facts-only layer; Microcosm owns which facts are targets, how they bind to the model, and the active subset. Observed values resolve from a hash-pinned Chronicle consumer-facts artifact at build time (identity only). Compilation to TargetSpec rows, the UK mapping module, and the metric providers for the declarative counterfactual kinds are microcosm#622; the calibration seam is microcosm#623.", + "allowed_value_operations": [ + "identity" + ], + "resolution_defaults": { + "base_period_policy": "latest_not_after_build_base_period", + "operation": "sum", + "assertion_policy": "observed_only" + }, + "registry_parity": { + "source_repository": "policyengine-uk-data", + "pinned_ref": "ebf733c", + "registry_rows": 651, + "mapped_rows": 609, + "excluded_rows": 42, + "mapped": { + "dwp/benefit_capped_households": "dwp.benefit_cap.capped_households", + "dwp/esa_claimants": "dwp.esa_claimants", + "dwp/esa_contrib_claimants": "dwp.esa_contrib_claimants", + "dwp/esa_income_claimants": "dwp.esa_income_claimants", + "dwp/jsa_claimants": "dwp.jsa_claimants", + "dwp/pip_dl_enhanced_claimants": "dwp.pip.daily_living_enhanced_claimants", + "dwp/pip_dl_standard_claimants": "dwp.pip.daily_living_standard_claimants", + "dwp/scotland_uc_households_child_under_1": "dwp.uc.scotland_households_child_under_1", + "dwp/uc/claimants_couple_no_children": "dwp.uc.households_couple_no_children", + "dwp/uc/claimants_couple_with_children": "dwp.uc.households_couple_with_children", + "dwp/uc/claimants_single_no_children": "dwp.uc.households_single_no_children", + "dwp/uc/claimants_single_with_children": "dwp.uc.households_single_with_children", + "dwp/uc/claimants_with_1_children": "dwp.uc.households_children_1", + "dwp/uc/claimants_with_2_children": "dwp.uc.households_children_2", + "dwp/uc/claimants_with_3_children": "dwp.uc.households_children_3", + "dwp/uc/claimants_with_4_children": "dwp.uc.households_children_4", + "dwp/uc/claimants_with_5+_children": "dwp.uc.households_children_5_or_more", + "dwp/uc/two_child_limit/3_children_households": "dwp.uc.two_child_limit.households_3_children", + "dwp/uc/two_child_limit/3_children_households_total_children": "dwp.uc.two_child_limit.children_in_3_children_households", + "dwp/uc/two_child_limit/4_children_households": "dwp.uc.two_child_limit.households_4_children", + "dwp/uc/two_child_limit/4_children_households_total_children": "dwp.uc.two_child_limit.children_in_4_children_households", + "dwp/uc/two_child_limit/5_children_households": "dwp.uc.two_child_limit.households_5_children", + "dwp/uc/two_child_limit/5_children_households_total_children": "dwp.uc.two_child_limit.children_in_5_children_households", + "dwp/uc/two_child_limit/6_children_households": "dwp.uc.two_child_limit.households_6_plus_children", + "dwp/uc/two_child_limit/6_children_households_total_children": "dwp.uc.two_child_limit.children_in_6_plus_children_households", + "dwp/uc/two_child_limit/adult_pip_children": "dwp.uc.two_child_limit.children_claimant_pip", + "dwp/uc/two_child_limit/adult_pip_households": "dwp.uc.two_child_limit.households_claimant_pip", + "dwp/uc/two_child_limit/children_affected": "dwp.uc.two_child_limit.children_affected", + "dwp/uc/two_child_limit/children_in_affected_households": "dwp.uc.two_child_limit.children_in_affected_households", + "dwp/uc/two_child_limit/disabled_child_element_children": "dwp.uc.two_child_limit.children_disabled_child_element", + "dwp/uc/two_child_limit/disabled_child_element_households": "dwp.uc.two_child_limit.households_disabled_child_element", + "dwp/uc/two_child_limit/households_affected": "dwp.uc.two_child_limit.households_affected", + "dwp/uc_payment_dist/COUPLE_NO_CHILDREN_annual_payment_0_to_1_200": "dwp.uc.payment_distribution_couple_no_children", + "dwp/uc_payment_dist/COUPLE_NO_CHILDREN_annual_payment_10_800_to_12_000": "dwp.uc.payment_distribution_couple_no_children", + "dwp/uc_payment_dist/COUPLE_NO_CHILDREN_annual_payment_12_000_to_13_200": "dwp.uc.payment_distribution_couple_no_children", + "dwp/uc_payment_dist/COUPLE_NO_CHILDREN_annual_payment_13_200_to_14_400": "dwp.uc.payment_distribution_couple_no_children", + "dwp/uc_payment_dist/COUPLE_NO_CHILDREN_annual_payment_14_400_to_15_600": "dwp.uc.payment_distribution_couple_no_children", + "dwp/uc_payment_dist/COUPLE_NO_CHILDREN_annual_payment_15_600_to_16_800": "dwp.uc.payment_distribution_couple_no_children", + "dwp/uc_payment_dist/COUPLE_NO_CHILDREN_annual_payment_16_800_to_18_000": "dwp.uc.payment_distribution_couple_no_children", + "dwp/uc_payment_dist/COUPLE_NO_CHILDREN_annual_payment_18_000_to_19_200": "dwp.uc.payment_distribution_couple_no_children", + "dwp/uc_payment_dist/COUPLE_NO_CHILDREN_annual_payment_19_200_to_20_400": "dwp.uc.payment_distribution_couple_no_children", + "dwp/uc_payment_dist/COUPLE_NO_CHILDREN_annual_payment_1_200_to_2_400": "dwp.uc.payment_distribution_couple_no_children", + "dwp/uc_payment_dist/COUPLE_NO_CHILDREN_annual_payment_20_400_to_21_600": "dwp.uc.payment_distribution_couple_no_children", + "dwp/uc_payment_dist/COUPLE_NO_CHILDREN_annual_payment_21_600_to_22_800": "dwp.uc.payment_distribution_couple_no_children", + "dwp/uc_payment_dist/COUPLE_NO_CHILDREN_annual_payment_22_800_to_24_000": "dwp.uc.payment_distribution_couple_no_children", + "dwp/uc_payment_dist/COUPLE_NO_CHILDREN_annual_payment_24_000_to_25_200": "dwp.uc.payment_distribution_couple_no_children", + "dwp/uc_payment_dist/COUPLE_NO_CHILDREN_annual_payment_25_200_to_26_400": "dwp.uc.payment_distribution_couple_no_children", + "dwp/uc_payment_dist/COUPLE_NO_CHILDREN_annual_payment_26_400_to_27_600": "dwp.uc.payment_distribution_couple_no_children", + "dwp/uc_payment_dist/COUPLE_NO_CHILDREN_annual_payment_27_600_to_28_800": "dwp.uc.payment_distribution_couple_no_children", + "dwp/uc_payment_dist/COUPLE_NO_CHILDREN_annual_payment_28_800_to_30_000": "dwp.uc.payment_distribution_couple_no_children", + "dwp/uc_payment_dist/COUPLE_NO_CHILDREN_annual_payment_2_400_to_3_600": "dwp.uc.payment_distribution_couple_no_children", + "dwp/uc_payment_dist/COUPLE_NO_CHILDREN_annual_payment_3_600_to_4_800": "dwp.uc.payment_distribution_couple_no_children", + "dwp/uc_payment_dist/COUPLE_NO_CHILDREN_annual_payment_4_800_to_6_000": "dwp.uc.payment_distribution_couple_no_children", + "dwp/uc_payment_dist/COUPLE_NO_CHILDREN_annual_payment_6_000_to_7_200": "dwp.uc.payment_distribution_couple_no_children", + "dwp/uc_payment_dist/COUPLE_NO_CHILDREN_annual_payment_7_200_to_8_400": "dwp.uc.payment_distribution_couple_no_children", + "dwp/uc_payment_dist/COUPLE_NO_CHILDREN_annual_payment_8_400_to_9_600": "dwp.uc.payment_distribution_couple_no_children", + "dwp/uc_payment_dist/COUPLE_NO_CHILDREN_annual_payment_9_600_to_10_800": "dwp.uc.payment_distribution_couple_no_children", + "dwp/uc_payment_dist/COUPLE_NO_CHILDREN_annual_payment_nan_to_nan": "dwp.uc.payment_distribution_couple_no_children", + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_0_to_1_200": "dwp.uc.payment_distribution_couple_with_children", + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_10_800_to_12_000": "dwp.uc.payment_distribution_couple_with_children", + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_12_000_to_13_200": "dwp.uc.payment_distribution_couple_with_children", + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_13_200_to_14_400": "dwp.uc.payment_distribution_couple_with_children", + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_14_400_to_15_600": "dwp.uc.payment_distribution_couple_with_children", + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_15_600_to_16_800": "dwp.uc.payment_distribution_couple_with_children", + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_16_800_to_18_000": "dwp.uc.payment_distribution_couple_with_children", + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_18_000_to_19_200": "dwp.uc.payment_distribution_couple_with_children", + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_19_200_to_20_400": "dwp.uc.payment_distribution_couple_with_children", + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_1_200_to_2_400": "dwp.uc.payment_distribution_couple_with_children", + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_20_400_to_21_600": "dwp.uc.payment_distribution_couple_with_children", + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_21_600_to_22_800": "dwp.uc.payment_distribution_couple_with_children", + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_22_800_to_24_000": "dwp.uc.payment_distribution_couple_with_children", + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_24_000_to_25_200": "dwp.uc.payment_distribution_couple_with_children", + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_25_200_to_26_400": "dwp.uc.payment_distribution_couple_with_children", + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_26_400_to_27_600": "dwp.uc.payment_distribution_couple_with_children", + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_27_600_to_28_800": "dwp.uc.payment_distribution_couple_with_children", + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_28_800_to_30_000": "dwp.uc.payment_distribution_couple_with_children", + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_2_400_to_3_600": "dwp.uc.payment_distribution_couple_with_children", + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_3_600_to_4_800": "dwp.uc.payment_distribution_couple_with_children", + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_4_800_to_6_000": "dwp.uc.payment_distribution_couple_with_children", + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_6_000_to_7_200": "dwp.uc.payment_distribution_couple_with_children", + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_7_200_to_8_400": "dwp.uc.payment_distribution_couple_with_children", + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_8_400_to_9_600": "dwp.uc.payment_distribution_couple_with_children", + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_9_600_to_10_800": "dwp.uc.payment_distribution_couple_with_children", + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_nan_to_nan": "dwp.uc.payment_distribution_couple_with_children", + "dwp/uc_payment_dist/LONE_PARENT_annual_payment_0_to_1_200": "dwp.uc.payment_distribution_lone_parent", + "dwp/uc_payment_dist/LONE_PARENT_annual_payment_10_800_to_12_000": "dwp.uc.payment_distribution_lone_parent", + "dwp/uc_payment_dist/LONE_PARENT_annual_payment_12_000_to_13_200": "dwp.uc.payment_distribution_lone_parent", + "dwp/uc_payment_dist/LONE_PARENT_annual_payment_13_200_to_14_400": "dwp.uc.payment_distribution_lone_parent", + "dwp/uc_payment_dist/LONE_PARENT_annual_payment_14_400_to_15_600": "dwp.uc.payment_distribution_lone_parent", + "dwp/uc_payment_dist/LONE_PARENT_annual_payment_15_600_to_16_800": "dwp.uc.payment_distribution_lone_parent", + "dwp/uc_payment_dist/LONE_PARENT_annual_payment_16_800_to_18_000": "dwp.uc.payment_distribution_lone_parent", + "dwp/uc_payment_dist/LONE_PARENT_annual_payment_18_000_to_19_200": "dwp.uc.payment_distribution_lone_parent", + "dwp/uc_payment_dist/LONE_PARENT_annual_payment_19_200_to_20_400": "dwp.uc.payment_distribution_lone_parent", + "dwp/uc_payment_dist/LONE_PARENT_annual_payment_1_200_to_2_400": "dwp.uc.payment_distribution_lone_parent", + "dwp/uc_payment_dist/LONE_PARENT_annual_payment_20_400_to_21_600": "dwp.uc.payment_distribution_lone_parent", + "dwp/uc_payment_dist/LONE_PARENT_annual_payment_21_600_to_22_800": "dwp.uc.payment_distribution_lone_parent", + "dwp/uc_payment_dist/LONE_PARENT_annual_payment_22_800_to_24_000": "dwp.uc.payment_distribution_lone_parent", + "dwp/uc_payment_dist/LONE_PARENT_annual_payment_24_000_to_25_200": "dwp.uc.payment_distribution_lone_parent", + "dwp/uc_payment_dist/LONE_PARENT_annual_payment_25_200_to_26_400": "dwp.uc.payment_distribution_lone_parent", + "dwp/uc_payment_dist/LONE_PARENT_annual_payment_26_400_to_27_600": "dwp.uc.payment_distribution_lone_parent", + "dwp/uc_payment_dist/LONE_PARENT_annual_payment_27_600_to_28_800": "dwp.uc.payment_distribution_lone_parent", + "dwp/uc_payment_dist/LONE_PARENT_annual_payment_28_800_to_30_000": "dwp.uc.payment_distribution_lone_parent", + "dwp/uc_payment_dist/LONE_PARENT_annual_payment_2_400_to_3_600": "dwp.uc.payment_distribution_lone_parent", + "dwp/uc_payment_dist/LONE_PARENT_annual_payment_3_600_to_4_800": "dwp.uc.payment_distribution_lone_parent", + "dwp/uc_payment_dist/LONE_PARENT_annual_payment_4_800_to_6_000": "dwp.uc.payment_distribution_lone_parent", + "dwp/uc_payment_dist/LONE_PARENT_annual_payment_6_000_to_7_200": "dwp.uc.payment_distribution_lone_parent", + "dwp/uc_payment_dist/LONE_PARENT_annual_payment_7_200_to_8_400": "dwp.uc.payment_distribution_lone_parent", + "dwp/uc_payment_dist/LONE_PARENT_annual_payment_8_400_to_9_600": "dwp.uc.payment_distribution_lone_parent", + "dwp/uc_payment_dist/LONE_PARENT_annual_payment_9_600_to_10_800": "dwp.uc.payment_distribution_lone_parent", + "dwp/uc_payment_dist/LONE_PARENT_annual_payment_nan_to_nan": "dwp.uc.payment_distribution_lone_parent", + "dwp/uc_payment_dist/SINGLE_annual_payment_0_to_1_200": "dwp.uc.payment_distribution_single", + "dwp/uc_payment_dist/SINGLE_annual_payment_10_800_to_12_000": "dwp.uc.payment_distribution_single", + "dwp/uc_payment_dist/SINGLE_annual_payment_12_000_to_13_200": "dwp.uc.payment_distribution_single", + "dwp/uc_payment_dist/SINGLE_annual_payment_13_200_to_14_400": "dwp.uc.payment_distribution_single", + "dwp/uc_payment_dist/SINGLE_annual_payment_14_400_to_15_600": "dwp.uc.payment_distribution_single", + "dwp/uc_payment_dist/SINGLE_annual_payment_15_600_to_16_800": "dwp.uc.payment_distribution_single", + "dwp/uc_payment_dist/SINGLE_annual_payment_16_800_to_18_000": "dwp.uc.payment_distribution_single", + "dwp/uc_payment_dist/SINGLE_annual_payment_18_000_to_19_200": "dwp.uc.payment_distribution_single", + "dwp/uc_payment_dist/SINGLE_annual_payment_19_200_to_20_400": "dwp.uc.payment_distribution_single", + "dwp/uc_payment_dist/SINGLE_annual_payment_1_200_to_2_400": "dwp.uc.payment_distribution_single", + "dwp/uc_payment_dist/SINGLE_annual_payment_20_400_to_21_600": "dwp.uc.payment_distribution_single", + "dwp/uc_payment_dist/SINGLE_annual_payment_21_600_to_22_800": "dwp.uc.payment_distribution_single", + "dwp/uc_payment_dist/SINGLE_annual_payment_22_800_to_24_000": "dwp.uc.payment_distribution_single", + "dwp/uc_payment_dist/SINGLE_annual_payment_24_000_to_25_200": "dwp.uc.payment_distribution_single", + "dwp/uc_payment_dist/SINGLE_annual_payment_25_200_to_26_400": "dwp.uc.payment_distribution_single", + "dwp/uc_payment_dist/SINGLE_annual_payment_26_400_to_27_600": "dwp.uc.payment_distribution_single", + "dwp/uc_payment_dist/SINGLE_annual_payment_27_600_to_28_800": "dwp.uc.payment_distribution_single", + "dwp/uc_payment_dist/SINGLE_annual_payment_28_800_to_30_000": "dwp.uc.payment_distribution_single", + "dwp/uc_payment_dist/SINGLE_annual_payment_2_400_to_3_600": "dwp.uc.payment_distribution_single", + "dwp/uc_payment_dist/SINGLE_annual_payment_3_600_to_4_800": "dwp.uc.payment_distribution_single", + "dwp/uc_payment_dist/SINGLE_annual_payment_4_800_to_6_000": "dwp.uc.payment_distribution_single", + "dwp/uc_payment_dist/SINGLE_annual_payment_6_000_to_7_200": "dwp.uc.payment_distribution_single", + "dwp/uc_payment_dist/SINGLE_annual_payment_7_200_to_8_400": "dwp.uc.payment_distribution_single", + "dwp/uc_payment_dist/SINGLE_annual_payment_8_400_to_9_600": "dwp.uc.payment_distribution_single", + "dwp/uc_payment_dist/SINGLE_annual_payment_9_600_to_10_800": "dwp.uc.payment_distribution_single", + "dwp/uc_payment_dist/SINGLE_annual_payment_nan_to_nan": "dwp.uc.payment_distribution_single", + "hmrc/capital_gains_total": "hmrc.cgt.gains_total", + "hmrc/cgt_taxpayers": "hmrc.cgt.taxpayers_total", + "hmrc/dividend_income_count_income_band_100_000_to_150_000": "hmrc.spi.dividend_income.count_by_total_income_band", + "hmrc/dividend_income_count_income_band_12_570_to_15_000": "hmrc.spi.dividend_income.count_by_total_income_band", + "hmrc/dividend_income_count_income_band_150_000_to_200_000": "hmrc.spi.dividend_income.count_by_total_income_band", + "hmrc/dividend_income_count_income_band_15_000_to_20_000": "hmrc.spi.dividend_income.count_by_total_income_band", + "hmrc/dividend_income_count_income_band_1_000_000_to_inf": "hmrc.spi.dividend_income.count_by_total_income_band", + "hmrc/dividend_income_count_income_band_200_000_to_300_000": "hmrc.spi.dividend_income.count_by_total_income_band", + "hmrc/dividend_income_count_income_band_20_000_to_30_000": "hmrc.spi.dividend_income.count_by_total_income_band", + "hmrc/dividend_income_count_income_band_300_000_to_500_000": "hmrc.spi.dividend_income.count_by_total_income_band", + "hmrc/dividend_income_count_income_band_30_000_to_40_000": "hmrc.spi.dividend_income.count_by_total_income_band", + "hmrc/dividend_income_count_income_band_40_000_to_50_000": "hmrc.spi.dividend_income.count_by_total_income_band", + "hmrc/dividend_income_count_income_band_500_000_to_1_000_000": "hmrc.spi.dividend_income.count_by_total_income_band", + "hmrc/dividend_income_count_income_band_50_000_to_70_000": "hmrc.spi.dividend_income.count_by_total_income_band", + "hmrc/dividend_income_count_income_band_70_000_to_100_000": "hmrc.spi.dividend_income.count_by_total_income_band", + "hmrc/dividend_income_income_band_100_000_to_150_000": "hmrc.spi.dividend_income.amount_by_total_income_band", + "hmrc/dividend_income_income_band_12_570_to_15_000": "hmrc.spi.dividend_income.amount_by_total_income_band", + "hmrc/dividend_income_income_band_150_000_to_200_000": "hmrc.spi.dividend_income.amount_by_total_income_band", + "hmrc/dividend_income_income_band_15_000_to_20_000": "hmrc.spi.dividend_income.amount_by_total_income_band", + "hmrc/dividend_income_income_band_1_000_000_to_inf": "hmrc.spi.dividend_income.amount_by_total_income_band", + "hmrc/dividend_income_income_band_200_000_to_300_000": "hmrc.spi.dividend_income.amount_by_total_income_band", + "hmrc/dividend_income_income_band_20_000_to_30_000": "hmrc.spi.dividend_income.amount_by_total_income_band", + "hmrc/dividend_income_income_band_300_000_to_500_000": "hmrc.spi.dividend_income.amount_by_total_income_band", + "hmrc/dividend_income_income_band_30_000_to_40_000": "hmrc.spi.dividend_income.amount_by_total_income_band", + "hmrc/dividend_income_income_band_40_000_to_50_000": "hmrc.spi.dividend_income.amount_by_total_income_band", + "hmrc/dividend_income_income_band_500_000_to_1_000_000": "hmrc.spi.dividend_income.amount_by_total_income_band", + "hmrc/dividend_income_income_band_50_000_to_70_000": "hmrc.spi.dividend_income.amount_by_total_income_band", + "hmrc/dividend_income_income_band_70_000_to_100_000": "hmrc.spi.dividend_income.amount_by_total_income_band", + "hmrc/employment_income_count_income_band_100_000_to_150_000": "hmrc.spi.employment_income.count_by_total_income_band", + "hmrc/employment_income_count_income_band_12_570_to_15_000": "hmrc.spi.employment_income.count_by_total_income_band", + "hmrc/employment_income_count_income_band_150_000_to_200_000": "hmrc.spi.employment_income.count_by_total_income_band", + "hmrc/employment_income_count_income_band_15_000_to_20_000": "hmrc.spi.employment_income.count_by_total_income_band", + "hmrc/employment_income_count_income_band_1_000_000_to_inf": "hmrc.spi.employment_income.count_by_total_income_band", + "hmrc/employment_income_count_income_band_200_000_to_300_000": "hmrc.spi.employment_income.count_by_total_income_band", + "hmrc/employment_income_count_income_band_20_000_to_30_000": "hmrc.spi.employment_income.count_by_total_income_band", + "hmrc/employment_income_count_income_band_300_000_to_500_000": "hmrc.spi.employment_income.count_by_total_income_band", + "hmrc/employment_income_count_income_band_30_000_to_40_000": "hmrc.spi.employment_income.count_by_total_income_band", + "hmrc/employment_income_count_income_band_40_000_to_50_000": "hmrc.spi.employment_income.count_by_total_income_band", + "hmrc/employment_income_count_income_band_500_000_to_1_000_000": "hmrc.spi.employment_income.count_by_total_income_band", + "hmrc/employment_income_count_income_band_50_000_to_70_000": "hmrc.spi.employment_income.count_by_total_income_band", + "hmrc/employment_income_count_income_band_70_000_to_100_000": "hmrc.spi.employment_income.count_by_total_income_band", + "hmrc/employment_income_income_band_100_000_to_150_000": "hmrc.spi.employment_income.amount_by_total_income_band", + "hmrc/employment_income_income_band_12_570_to_15_000": "hmrc.spi.employment_income.amount_by_total_income_band", + "hmrc/employment_income_income_band_150_000_to_200_000": "hmrc.spi.employment_income.amount_by_total_income_band", + "hmrc/employment_income_income_band_15_000_to_20_000": "hmrc.spi.employment_income.amount_by_total_income_band", + "hmrc/employment_income_income_band_1_000_000_to_inf": "hmrc.spi.employment_income.amount_by_total_income_band", + "hmrc/employment_income_income_band_200_000_to_300_000": "hmrc.spi.employment_income.amount_by_total_income_band", + "hmrc/employment_income_income_band_20_000_to_30_000": "hmrc.spi.employment_income.amount_by_total_income_band", + "hmrc/employment_income_income_band_300_000_to_500_000": "hmrc.spi.employment_income.amount_by_total_income_band", + "hmrc/employment_income_income_band_30_000_to_40_000": "hmrc.spi.employment_income.amount_by_total_income_band", + "hmrc/employment_income_income_band_40_000_to_50_000": "hmrc.spi.employment_income.amount_by_total_income_band", + "hmrc/employment_income_income_band_500_000_to_1_000_000": "hmrc.spi.employment_income.amount_by_total_income_band", + "hmrc/employment_income_income_band_50_000_to_70_000": "hmrc.spi.employment_income.amount_by_total_income_band", + "hmrc/employment_income_income_band_70_000_to_100_000": "hmrc.spi.employment_income.amount_by_total_income_band", + "hmrc/private_pension_income_count_income_band_100_000_to_150_000": "hmrc.spi.private_pension_income.count_by_total_income_band", + "hmrc/private_pension_income_count_income_band_12_570_to_15_000": "hmrc.spi.private_pension_income.count_by_total_income_band", + "hmrc/private_pension_income_count_income_band_150_000_to_200_000": "hmrc.spi.private_pension_income.count_by_total_income_band", + "hmrc/private_pension_income_count_income_band_15_000_to_20_000": "hmrc.spi.private_pension_income.count_by_total_income_band", + "hmrc/private_pension_income_count_income_band_1_000_000_to_inf": "hmrc.spi.private_pension_income.count_by_total_income_band", + "hmrc/private_pension_income_count_income_band_200_000_to_300_000": "hmrc.spi.private_pension_income.count_by_total_income_band", + "hmrc/private_pension_income_count_income_band_20_000_to_30_000": "hmrc.spi.private_pension_income.count_by_total_income_band", + "hmrc/private_pension_income_count_income_band_300_000_to_500_000": "hmrc.spi.private_pension_income.count_by_total_income_band", + "hmrc/private_pension_income_count_income_band_30_000_to_40_000": "hmrc.spi.private_pension_income.count_by_total_income_band", + "hmrc/private_pension_income_count_income_band_40_000_to_50_000": "hmrc.spi.private_pension_income.count_by_total_income_band", + "hmrc/private_pension_income_count_income_band_500_000_to_1_000_000": "hmrc.spi.private_pension_income.count_by_total_income_band", + "hmrc/private_pension_income_count_income_band_50_000_to_70_000": "hmrc.spi.private_pension_income.count_by_total_income_band", + "hmrc/private_pension_income_count_income_band_70_000_to_100_000": "hmrc.spi.private_pension_income.count_by_total_income_band", + "hmrc/private_pension_income_income_band_100_000_to_150_000": "hmrc.spi.private_pension_income.amount_by_total_income_band", + "hmrc/private_pension_income_income_band_12_570_to_15_000": "hmrc.spi.private_pension_income.amount_by_total_income_band", + "hmrc/private_pension_income_income_band_150_000_to_200_000": "hmrc.spi.private_pension_income.amount_by_total_income_band", + "hmrc/private_pension_income_income_band_15_000_to_20_000": "hmrc.spi.private_pension_income.amount_by_total_income_band", + "hmrc/private_pension_income_income_band_1_000_000_to_inf": "hmrc.spi.private_pension_income.amount_by_total_income_band", + "hmrc/private_pension_income_income_band_200_000_to_300_000": "hmrc.spi.private_pension_income.amount_by_total_income_band", + "hmrc/private_pension_income_income_band_20_000_to_30_000": "hmrc.spi.private_pension_income.amount_by_total_income_band", + "hmrc/private_pension_income_income_band_300_000_to_500_000": "hmrc.spi.private_pension_income.amount_by_total_income_band", + "hmrc/private_pension_income_income_band_30_000_to_40_000": "hmrc.spi.private_pension_income.amount_by_total_income_band", + "hmrc/private_pension_income_income_band_40_000_to_50_000": "hmrc.spi.private_pension_income.amount_by_total_income_band", + "hmrc/private_pension_income_income_band_500_000_to_1_000_000": "hmrc.spi.private_pension_income.amount_by_total_income_band", + "hmrc/private_pension_income_income_band_50_000_to_70_000": "hmrc.spi.private_pension_income.amount_by_total_income_band", + "hmrc/private_pension_income_income_band_70_000_to_100_000": "hmrc.spi.private_pension_income.amount_by_total_income_band", + "hmrc/property_income_count_income_band_100_000_to_150_000": "hmrc.spi.property_income.count_by_total_income_band", + "hmrc/property_income_count_income_band_12_570_to_15_000": "hmrc.spi.property_income.count_by_total_income_band", + "hmrc/property_income_count_income_band_150_000_to_200_000": "hmrc.spi.property_income.count_by_total_income_band", + "hmrc/property_income_count_income_band_15_000_to_20_000": "hmrc.spi.property_income.count_by_total_income_band", + "hmrc/property_income_count_income_band_1_000_000_to_inf": "hmrc.spi.property_income.count_by_total_income_band", + "hmrc/property_income_count_income_band_200_000_to_300_000": "hmrc.spi.property_income.count_by_total_income_band", + "hmrc/property_income_count_income_band_20_000_to_30_000": "hmrc.spi.property_income.count_by_total_income_band", + "hmrc/property_income_count_income_band_300_000_to_500_000": "hmrc.spi.property_income.count_by_total_income_band", + "hmrc/property_income_count_income_band_30_000_to_40_000": "hmrc.spi.property_income.count_by_total_income_band", + "hmrc/property_income_count_income_band_40_000_to_50_000": "hmrc.spi.property_income.count_by_total_income_band", + "hmrc/property_income_count_income_band_500_000_to_1_000_000": "hmrc.spi.property_income.count_by_total_income_band", + "hmrc/property_income_count_income_band_50_000_to_70_000": "hmrc.spi.property_income.count_by_total_income_band", + "hmrc/property_income_count_income_band_70_000_to_100_000": "hmrc.spi.property_income.count_by_total_income_band", + "hmrc/property_income_income_band_100_000_to_150_000": "hmrc.spi.property_income.amount_by_total_income_band", + "hmrc/property_income_income_band_12_570_to_15_000": "hmrc.spi.property_income.amount_by_total_income_band", + "hmrc/property_income_income_band_150_000_to_200_000": "hmrc.spi.property_income.amount_by_total_income_band", + "hmrc/property_income_income_band_15_000_to_20_000": "hmrc.spi.property_income.amount_by_total_income_band", + "hmrc/property_income_income_band_1_000_000_to_inf": "hmrc.spi.property_income.amount_by_total_income_band", + "hmrc/property_income_income_band_200_000_to_300_000": "hmrc.spi.property_income.amount_by_total_income_band", + "hmrc/property_income_income_band_20_000_to_30_000": "hmrc.spi.property_income.amount_by_total_income_band", + "hmrc/property_income_income_band_300_000_to_500_000": "hmrc.spi.property_income.amount_by_total_income_band", + "hmrc/property_income_income_band_30_000_to_40_000": "hmrc.spi.property_income.amount_by_total_income_band", + "hmrc/property_income_income_band_40_000_to_50_000": "hmrc.spi.property_income.amount_by_total_income_band", + "hmrc/property_income_income_band_500_000_to_1_000_000": "hmrc.spi.property_income.amount_by_total_income_band", + "hmrc/property_income_income_band_50_000_to_70_000": "hmrc.spi.property_income.amount_by_total_income_band", + "hmrc/property_income_income_band_70_000_to_100_000": "hmrc.spi.property_income.amount_by_total_income_band", + "hmrc/self_employment_income_count_income_band_100_000_to_150_000": "hmrc.spi.self_employment_income.count_by_total_income_band", + "hmrc/self_employment_income_count_income_band_12_570_to_15_000": "hmrc.spi.self_employment_income.count_by_total_income_band", + "hmrc/self_employment_income_count_income_band_150_000_to_200_000": "hmrc.spi.self_employment_income.count_by_total_income_band", + "hmrc/self_employment_income_count_income_band_15_000_to_20_000": "hmrc.spi.self_employment_income.count_by_total_income_band", + "hmrc/self_employment_income_count_income_band_1_000_000_to_inf": "hmrc.spi.self_employment_income.count_by_total_income_band", + "hmrc/self_employment_income_count_income_band_200_000_to_300_000": "hmrc.spi.self_employment_income.count_by_total_income_band", + "hmrc/self_employment_income_count_income_band_20_000_to_30_000": "hmrc.spi.self_employment_income.count_by_total_income_band", + "hmrc/self_employment_income_count_income_band_300_000_to_500_000": "hmrc.spi.self_employment_income.count_by_total_income_band", + "hmrc/self_employment_income_count_income_band_30_000_to_40_000": "hmrc.spi.self_employment_income.count_by_total_income_band", + "hmrc/self_employment_income_count_income_band_40_000_to_50_000": "hmrc.spi.self_employment_income.count_by_total_income_band", + "hmrc/self_employment_income_count_income_band_500_000_to_1_000_000": "hmrc.spi.self_employment_income.count_by_total_income_band", + "hmrc/self_employment_income_count_income_band_50_000_to_70_000": "hmrc.spi.self_employment_income.count_by_total_income_band", + "hmrc/self_employment_income_count_income_band_70_000_to_100_000": "hmrc.spi.self_employment_income.count_by_total_income_band", + "hmrc/self_employment_income_income_band_100_000_to_150_000": "hmrc.spi.self_employment_income.amount_by_total_income_band", + "hmrc/self_employment_income_income_band_12_570_to_15_000": "hmrc.spi.self_employment_income.amount_by_total_income_band", + "hmrc/self_employment_income_income_band_150_000_to_200_000": "hmrc.spi.self_employment_income.amount_by_total_income_band", + "hmrc/self_employment_income_income_band_15_000_to_20_000": "hmrc.spi.self_employment_income.amount_by_total_income_band", + "hmrc/self_employment_income_income_band_1_000_000_to_inf": "hmrc.spi.self_employment_income.amount_by_total_income_band", + "hmrc/self_employment_income_income_band_200_000_to_300_000": "hmrc.spi.self_employment_income.amount_by_total_income_band", + "hmrc/self_employment_income_income_band_20_000_to_30_000": "hmrc.spi.self_employment_income.amount_by_total_income_band", + "hmrc/self_employment_income_income_band_300_000_to_500_000": "hmrc.spi.self_employment_income.amount_by_total_income_band", + "hmrc/self_employment_income_income_band_30_000_to_40_000": "hmrc.spi.self_employment_income.amount_by_total_income_band", + "hmrc/self_employment_income_income_band_40_000_to_50_000": "hmrc.spi.self_employment_income.amount_by_total_income_band", + "hmrc/self_employment_income_income_band_500_000_to_1_000_000": "hmrc.spi.self_employment_income.amount_by_total_income_band", + "hmrc/self_employment_income_income_band_50_000_to_70_000": "hmrc.spi.self_employment_income.amount_by_total_income_band", + "hmrc/self_employment_income_income_band_70_000_to_100_000": "hmrc.spi.self_employment_income.amount_by_total_income_band", + "hmrc/state_pension_count_income_band_100_000_to_150_000": "hmrc.spi.state_pension.count_by_total_income_band", + "hmrc/state_pension_count_income_band_12_570_to_15_000": "hmrc.spi.state_pension.count_by_total_income_band", + "hmrc/state_pension_count_income_band_150_000_to_200_000": "hmrc.spi.state_pension.count_by_total_income_band", + "hmrc/state_pension_count_income_band_15_000_to_20_000": "hmrc.spi.state_pension.count_by_total_income_band", + "hmrc/state_pension_count_income_band_1_000_000_to_inf": "hmrc.spi.state_pension.count_by_total_income_band", + "hmrc/state_pension_count_income_band_200_000_to_300_000": "hmrc.spi.state_pension.count_by_total_income_band", + "hmrc/state_pension_count_income_band_20_000_to_30_000": "hmrc.spi.state_pension.count_by_total_income_band", + "hmrc/state_pension_count_income_band_300_000_to_500_000": "hmrc.spi.state_pension.count_by_total_income_band", + "hmrc/state_pension_count_income_band_30_000_to_40_000": "hmrc.spi.state_pension.count_by_total_income_band", + "hmrc/state_pension_count_income_band_40_000_to_50_000": "hmrc.spi.state_pension.count_by_total_income_band", + "hmrc/state_pension_count_income_band_500_000_to_1_000_000": "hmrc.spi.state_pension.count_by_total_income_band", + "hmrc/state_pension_count_income_band_50_000_to_70_000": "hmrc.spi.state_pension.count_by_total_income_band", + "hmrc/state_pension_count_income_band_70_000_to_100_000": "hmrc.spi.state_pension.count_by_total_income_band", + "hmrc/state_pension_income_band_100_000_to_150_000": "hmrc.spi.state_pension.amount_by_total_income_band", + "hmrc/state_pension_income_band_12_570_to_15_000": "hmrc.spi.state_pension.amount_by_total_income_band", + "hmrc/state_pension_income_band_150_000_to_200_000": "hmrc.spi.state_pension.amount_by_total_income_band", + "hmrc/state_pension_income_band_15_000_to_20_000": "hmrc.spi.state_pension.amount_by_total_income_band", + "hmrc/state_pension_income_band_1_000_000_to_inf": "hmrc.spi.state_pension.amount_by_total_income_band", + "hmrc/state_pension_income_band_200_000_to_300_000": "hmrc.spi.state_pension.amount_by_total_income_band", + "hmrc/state_pension_income_band_20_000_to_30_000": "hmrc.spi.state_pension.amount_by_total_income_band", + "hmrc/state_pension_income_band_300_000_to_500_000": "hmrc.spi.state_pension.amount_by_total_income_band", + "hmrc/state_pension_income_band_30_000_to_40_000": "hmrc.spi.state_pension.amount_by_total_income_band", + "hmrc/state_pension_income_band_40_000_to_50_000": "hmrc.spi.state_pension.amount_by_total_income_band", + "hmrc/state_pension_income_band_500_000_to_1_000_000": "hmrc.spi.state_pension.amount_by_total_income_band", + "hmrc/state_pension_income_band_50_000_to_70_000": "hmrc.spi.state_pension.amount_by_total_income_band", + "hmrc/state_pension_income_band_70_000_to_100_000": "hmrc.spi.state_pension.amount_by_total_income_band", + "obr/attendance_allowance": "obr.attendance_allowance", + "obr/capital_gains_tax": "obr.capital_gains_tax", + "obr/carers_allowance": "obr.carers_allowance", + "obr/child_benefit": "obr.child_benefit", + "obr/council_tax": "obr.council_tax", + "obr/council_tax_england": "obr.council_tax_england", + "obr/council_tax_scotland": "obr.council_tax_scotland", + "obr/council_tax_wales": "obr.council_tax_wales", + "obr/domestic_rates": "obr.domestic_rates", + "obr/esa": "obr.esa", + "obr/fuel_duties": "obr.fuel_duties", + "obr/housing_benefit": "obr.housing_benefit", + "obr/income_tax": "obr.income_tax", + "obr/jobseekers_allowance": "obr.jobseekers_allowance", + "obr/ni": "obr.ni", + "obr/ni_employee": "obr.ni_employee", + "obr/ni_employer": "obr.ni_employer", + "obr/ni_self_employed": "obr.ni_self_employed", + "obr/pension_credit": "obr.pension_credit", + "obr/pip": "obr.pip", + "obr/private_school_students": "isc.private_school_students", + "obr/salary_sacrifice_employee_ni_relief": "hmrc.salary_sacrifice.nics_relief_employee", + "obr/salary_sacrifice_employer_ni_relief": "hmrc.salary_sacrifice.nics_relief_employer", + "obr/salary_sacrifice_users_above_cap": "hmrc.salary_sacrifice.users_above_cap", + "obr/salary_sacrifice_users_below_cap": "hmrc.salary_sacrifice.users_below_cap", + "obr/salary_sacrifice_users_total": "hmrc.salary_sacrifice.users_total", + "obr/sdlt": "obr.sdlt", + "obr/state_pension": "obr.state_pension", + "obr/statutory_maternity_pay": "obr.statutory_maternity_pay", + "obr/tv_licence_fee": "obr.tv_licence_fee", + "obr/universal_credit_in_cap": "obr.universal_credit_in_cap", + "obr/universal_credit_outside_cap": "obr.universal_credit_outside_cap", + "obr/vat": "obr.vat", + "obr/winter_fuel_allowance": "obr.winter_fuel_allowance", + "ons/corporate_land_value": "ons.land.corporate_land_value", + "ons/couple_3_plus_children_households": "ons.household_composition.couple_3_plus_children_households", + "ons/couple_no_children_households": "ons.household_composition.couple_no_children_households", + "ons/couple_non_dependent_children_only_households": "ons.household_composition.couple_non_dependent_children_only_households", + "ons/couple_under_3_children_households": "ons.household_composition.couple_under_3_children_households", + "ons/east_age_0_9": "ons.population.age_0_9_by_region", + "ons/east_age_10_19": "ons.population.age_10_19_by_region", + "ons/east_age_20_29": "ons.population.age_20_29_by_region", + "ons/east_age_30_39": "ons.population.age_30_39_by_region", + "ons/east_age_40_49": "ons.population.age_40_49_by_region", + "ons/east_age_50_59": "ons.population.age_50_59_by_region", + "ons/east_age_60_69": "ons.population.age_60_69_by_region", + "ons/east_age_70_79": "ons.population.age_70_79_by_region", + "ons/east_age_80_89": "ons.population.age_80_89_by_region", + "ons/east_midlands_age_0_9": "ons.population.age_0_9_by_region", + "ons/east_midlands_age_10_19": "ons.population.age_10_19_by_region", + "ons/east_midlands_age_20_29": "ons.population.age_20_29_by_region", + "ons/east_midlands_age_30_39": "ons.population.age_30_39_by_region", + "ons/east_midlands_age_40_49": "ons.population.age_40_49_by_region", + "ons/east_midlands_age_50_59": "ons.population.age_50_59_by_region", + "ons/east_midlands_age_60_69": "ons.population.age_60_69_by_region", + "ons/east_midlands_age_70_79": "ons.population.age_70_79_by_region", + "ons/east_midlands_age_80_89": "ons.population.age_80_89_by_region", + "ons/female_0_4": "ons.population.female_0_4", + "ons/female_10_14": "ons.population.female_10_14", + "ons/female_15_19": "ons.population.female_15_19", + "ons/female_20_24": "ons.population.female_20_24", + "ons/female_25_29": "ons.population.female_25_29", + "ons/female_30_34": "ons.population.female_30_34", + "ons/female_35_39": "ons.population.female_35_39", + "ons/female_40_44": "ons.population.female_40_44", + "ons/female_45_49": "ons.population.female_45_49", + "ons/female_50_54": "ons.population.female_50_54", + "ons/female_55_59": "ons.population.female_55_59", + "ons/female_5_9": "ons.population.female_5_9", + "ons/female_60_64": "ons.population.female_60_64", + "ons/female_65_69": "ons.population.female_65_69", + "ons/female_70_74": "ons.population.female_70_74", + "ons/female_75_79": "ons.population.female_75_79", + "ons/female_80_84": "ons.population.female_80_84", + "ons/female_85_90": "ons.population.female_85_90", + "ons/household_land_value": "ons.land.household_land_value", + "ons/land_value": "ons.land.land_value", + "ons/london_age_0_9": "ons.population.age_0_9_by_region", + "ons/london_age_10_19": "ons.population.age_10_19_by_region", + "ons/london_age_20_29": "ons.population.age_20_29_by_region", + "ons/london_age_30_39": "ons.population.age_30_39_by_region", + "ons/london_age_40_49": "ons.population.age_40_49_by_region", + "ons/london_age_50_59": "ons.population.age_50_59_by_region", + "ons/london_age_60_69": "ons.population.age_60_69_by_region", + "ons/london_age_70_79": "ons.population.age_70_79_by_region", + "ons/london_age_80_89": "ons.population.age_80_89_by_region", + "ons/lone_households_over_65": "ons.household_composition.lone_households_over_65", + "ons/lone_households_under_65": "ons.household_composition.lone_households_under_65", + "ons/lone_parent_dependent_children_households": "ons.household_composition.lone_parent_dependent_children_households", + "ons/lone_parent_non_dependent_children_households": "ons.household_composition.lone_parent_non_dependent_children_households", + "ons/male_0_4": "ons.population.male_0_4", + "ons/male_10_14": "ons.population.male_10_14", + "ons/male_15_19": "ons.population.male_15_19", + "ons/male_20_24": "ons.population.male_20_24", + "ons/male_25_29": "ons.population.male_25_29", + "ons/male_30_34": "ons.population.male_30_34", + "ons/male_35_39": "ons.population.male_35_39", + "ons/male_40_44": "ons.population.male_40_44", + "ons/male_45_49": "ons.population.male_45_49", + "ons/male_50_54": "ons.population.male_50_54", + "ons/male_55_59": "ons.population.male_55_59", + "ons/male_5_9": "ons.population.male_5_9", + "ons/male_60_64": "ons.population.male_60_64", + "ons/male_65_69": "ons.population.male_65_69", + "ons/male_70_74": "ons.population.male_70_74", + "ons/male_75_79": "ons.population.male_75_79", + "ons/male_80_84": "ons.population.male_80_84", + "ons/male_85_90": "ons.population.male_85_90", + "ons/multi_family_households": "ons.household_composition.multi_family_households", + "ons/north_east_age_0_9": "ons.population.age_0_9_by_region", + "ons/north_east_age_10_19": "ons.population.age_10_19_by_region", + "ons/north_east_age_20_29": "ons.population.age_20_29_by_region", + "ons/north_east_age_30_39": "ons.population.age_30_39_by_region", + "ons/north_east_age_40_49": "ons.population.age_40_49_by_region", + "ons/north_east_age_50_59": "ons.population.age_50_59_by_region", + "ons/north_east_age_60_69": "ons.population.age_60_69_by_region", + "ons/north_east_age_70_79": "ons.population.age_70_79_by_region", + "ons/north_east_age_80_89": "ons.population.age_80_89_by_region", + "ons/north_west_age_0_9": "ons.population.age_0_9_by_region", + "ons/north_west_age_10_19": "ons.population.age_10_19_by_region", + "ons/north_west_age_20_29": "ons.population.age_20_29_by_region", + "ons/north_west_age_30_39": "ons.population.age_30_39_by_region", + "ons/north_west_age_40_49": "ons.population.age_40_49_by_region", + "ons/north_west_age_50_59": "ons.population.age_50_59_by_region", + "ons/north_west_age_60_69": "ons.population.age_60_69_by_region", + "ons/north_west_age_70_79": "ons.population.age_70_79_by_region", + "ons/north_west_age_80_89": "ons.population.age_80_89_by_region", + "ons/northern_ireland_age_0_9": "ons.population.age_0_9_by_region", + "ons/northern_ireland_age_10_19": "ons.population.age_10_19_by_region", + "ons/northern_ireland_age_20_29": "ons.population.age_20_29_by_region", + "ons/northern_ireland_age_30_39": "ons.population.age_30_39_by_region", + "ons/northern_ireland_age_40_49": "ons.population.age_40_49_by_region", + "ons/northern_ireland_age_50_59": "ons.population.age_50_59_by_region", + "ons/northern_ireland_age_60_69": "ons.population.age_60_69_by_region", + "ons/northern_ireland_age_70_79": "ons.population.age_70_79_by_region", + "ons/northern_ireland_age_80_89": "ons.population.age_80_89_by_region", + "ons/public_sector_employment": "ons.public_sector_employment", + "ons/savings_interest_income": "ons.savings_interest_income", + "ons/scotland_age_0_9": "ons.population.age_0_9_by_region", + "ons/scotland_age_10_19": "ons.population.age_10_19_by_region", + "ons/scotland_age_20_29": "ons.population.age_20_29_by_region", + "ons/scotland_age_30_39": "ons.population.age_30_39_by_region", + "ons/scotland_age_40_49": "ons.population.age_40_49_by_region", + "ons/scotland_age_50_59": "ons.population.age_50_59_by_region", + "ons/scotland_age_60_69": "ons.population.age_60_69_by_region", + "ons/scotland_age_70_79": "ons.population.age_70_79_by_region", + "ons/scotland_age_80_89": "ons.population.age_80_89_by_region", + "ons/scotland_babies_under_1": "ons.population.scotland_babies_under_1", + "ons/scotland_children_under_16": "ons.population.scotland_children_under_16", + "ons/scotland_households_3plus_children": "ons.population.scotland_households_3plus_children", + "ons/south_east_age_0_9": "ons.population.age_0_9_by_region", + "ons/south_east_age_10_19": "ons.population.age_10_19_by_region", + "ons/south_east_age_20_29": "ons.population.age_20_29_by_region", + "ons/south_east_age_30_39": "ons.population.age_30_39_by_region", + "ons/south_east_age_40_49": "ons.population.age_40_49_by_region", + "ons/south_east_age_50_59": "ons.population.age_50_59_by_region", + "ons/south_east_age_60_69": "ons.population.age_60_69_by_region", + "ons/south_east_age_70_79": "ons.population.age_70_79_by_region", + "ons/south_east_age_80_89": "ons.population.age_80_89_by_region", + "ons/south_west_age_0_9": "ons.population.age_0_9_by_region", + "ons/south_west_age_10_19": "ons.population.age_10_19_by_region", + "ons/south_west_age_20_29": "ons.population.age_20_29_by_region", + "ons/south_west_age_30_39": "ons.population.age_30_39_by_region", + "ons/south_west_age_40_49": "ons.population.age_40_49_by_region", + "ons/south_west_age_50_59": "ons.population.age_50_59_by_region", + "ons/south_west_age_60_69": "ons.population.age_60_69_by_region", + "ons/south_west_age_70_79": "ons.population.age_70_79_by_region", + "ons/south_west_age_80_89": "ons.population.age_80_89_by_region", + "ons/uk_population": "ons.population.uk_total", + "ons/unrelated_adult_households": "ons.household_composition.unrelated_adult_households", + "ons/wales_age_0_9": "ons.population.age_0_9_by_region", + "ons/wales_age_10_19": "ons.population.age_10_19_by_region", + "ons/wales_age_20_29": "ons.population.age_20_29_by_region", + "ons/wales_age_30_39": "ons.population.age_30_39_by_region", + "ons/wales_age_40_49": "ons.population.age_40_49_by_region", + "ons/wales_age_50_59": "ons.population.age_50_59_by_region", + "ons/wales_age_60_69": "ons.population.age_60_69_by_region", + "ons/wales_age_70_79": "ons.population.age_70_79_by_region", + "ons/wales_age_80_89": "ons.population.age_80_89_by_region", + "ons/west_midlands_age_0_9": "ons.population.age_0_9_by_region", + "ons/west_midlands_age_10_19": "ons.population.age_10_19_by_region", + "ons/west_midlands_age_20_29": "ons.population.age_20_29_by_region", + "ons/west_midlands_age_30_39": "ons.population.age_30_39_by_region", + "ons/west_midlands_age_40_49": "ons.population.age_40_49_by_region", + "ons/west_midlands_age_50_59": "ons.population.age_50_59_by_region", + "ons/west_midlands_age_60_69": "ons.population.age_60_69_by_region", + "ons/west_midlands_age_70_79": "ons.population.age_70_79_by_region", + "ons/west_midlands_age_80_89": "ons.population.age_80_89_by_region", + "ons/yorkshire_and_the_humber_age_0_9": "ons.population.age_0_9_by_region", + "ons/yorkshire_and_the_humber_age_10_19": "ons.population.age_10_19_by_region", + "ons/yorkshire_and_the_humber_age_20_29": "ons.population.age_20_29_by_region", + "ons/yorkshire_and_the_humber_age_30_39": "ons.population.age_30_39_by_region", + "ons/yorkshire_and_the_humber_age_40_49": "ons.population.age_40_49_by_region", + "ons/yorkshire_and_the_humber_age_50_59": "ons.population.age_50_59_by_region", + "ons/yorkshire_and_the_humber_age_60_69": "ons.population.age_60_69_by_region", + "ons/yorkshire_and_the_humber_age_70_79": "ons.population.age_70_79_by_region", + "ons/yorkshire_and_the_humber_age_80_89": "ons.population.age_80_89_by_region", + "slc/adult_dependants_grant_recipients": "slc.support.adult_dependants_grant_recipients", + "slc/adult_dependants_grant_spend": "slc.support.adult_dependants_grant_spend", + "slc/maintenance_loan_recipients": "slc.support.maintenance_loan_recipients", + "slc/maintenance_loan_spend": "slc.support.maintenance_loan_spend", + "slc/parents_learning_allowance_recipients": "slc.support.parents_learning_allowance_recipients", + "slc/parents_learning_allowance_spend": "slc.support.parents_learning_allowance_spend", + "slc/plan_2_borrowers_above_threshold": "slc.borrowers.plan_2_above_threshold", + "slc/plan_2_borrowers_liable": "slc.borrowers.plan_2_liable", + "slc/plan_5_borrowers_above_threshold": "slc.borrowers.plan_5_above_threshold", + "slc/plan_5_borrowers_liable": "slc.borrowers.plan_5_liable", + "slc/student_loan_repayment/england": "slc.repayments.england_total_higher_education", + "slc/student_loan_repayment/england/plan_1": "slc.repayments.england_plan_1", + "slc/student_loan_repayment/england/plan_2": "slc.repayments.england_plan_2", + "slc/student_loan_repayment/england/plan_5": "slc.repayments.england_plan_5", + "slc/student_loan_repayment/england/postgraduate": "slc.repayments.england_postgraduate", + "slc/student_loan_repayment/northern_ireland": "slc.repayments.devolved_total", + "slc/student_loan_repayment/scotland": "slc.repayments.devolved_total", + "slc/student_loan_repayment/wales": "slc.repayments.devolved_total", + "sss/scottish_child_payment": "scotgov.scottish_child_payment_spending", + "voa/council_tax/EAST_MIDLANDS/A": "voa.council_tax_stock.band_a", + "voa/council_tax/EAST_MIDLANDS/B": "voa.council_tax_stock.band_b", + "voa/council_tax/EAST_MIDLANDS/C": "voa.council_tax_stock.band_c", + "voa/council_tax/EAST_MIDLANDS/D": "voa.council_tax_stock.band_d", + "voa/council_tax/EAST_MIDLANDS/E": "voa.council_tax_stock.band_e", + "voa/council_tax/EAST_MIDLANDS/F": "voa.council_tax_stock.band_f", + "voa/council_tax/EAST_MIDLANDS/G": "voa.council_tax_stock.band_g", + "voa/council_tax/EAST_MIDLANDS/H": "voa.council_tax_stock.band_h", + "voa/council_tax/EAST_MIDLANDS/total": "voa.council_tax_stock.total", + "voa/council_tax/EAST_OF_ENGLAND/A": "voa.council_tax_stock.band_a", + "voa/council_tax/EAST_OF_ENGLAND/B": "voa.council_tax_stock.band_b", + "voa/council_tax/EAST_OF_ENGLAND/C": "voa.council_tax_stock.band_c", + "voa/council_tax/EAST_OF_ENGLAND/D": "voa.council_tax_stock.band_d", + "voa/council_tax/EAST_OF_ENGLAND/E": "voa.council_tax_stock.band_e", + "voa/council_tax/EAST_OF_ENGLAND/F": "voa.council_tax_stock.band_f", + "voa/council_tax/EAST_OF_ENGLAND/G": "voa.council_tax_stock.band_g", + "voa/council_tax/EAST_OF_ENGLAND/H": "voa.council_tax_stock.band_h", + "voa/council_tax/EAST_OF_ENGLAND/total": "voa.council_tax_stock.total", + "voa/council_tax/LONDON/A": "voa.council_tax_stock.band_a", + "voa/council_tax/LONDON/B": "voa.council_tax_stock.band_b", + "voa/council_tax/LONDON/C": "voa.council_tax_stock.band_c", + "voa/council_tax/LONDON/D": "voa.council_tax_stock.band_d", + "voa/council_tax/LONDON/E": "voa.council_tax_stock.band_e", + "voa/council_tax/LONDON/F": "voa.council_tax_stock.band_f", + "voa/council_tax/LONDON/G": "voa.council_tax_stock.band_g", + "voa/council_tax/LONDON/H": "voa.council_tax_stock.band_h", + "voa/council_tax/LONDON/total": "voa.council_tax_stock.total", + "voa/council_tax/NORTH_EAST/A": "voa.council_tax_stock.band_a", + "voa/council_tax/NORTH_EAST/B": "voa.council_tax_stock.band_b", + "voa/council_tax/NORTH_EAST/C": "voa.council_tax_stock.band_c", + "voa/council_tax/NORTH_EAST/D": "voa.council_tax_stock.band_d", + "voa/council_tax/NORTH_EAST/E": "voa.council_tax_stock.band_e", + "voa/council_tax/NORTH_EAST/F": "voa.council_tax_stock.band_f", + "voa/council_tax/NORTH_EAST/G": "voa.council_tax_stock.band_g", + "voa/council_tax/NORTH_EAST/H": "voa.council_tax_stock.band_h", + "voa/council_tax/NORTH_EAST/total": "voa.council_tax_stock.total", + "voa/council_tax/NORTH_WEST/A": "voa.council_tax_stock.band_a", + "voa/council_tax/NORTH_WEST/B": "voa.council_tax_stock.band_b", + "voa/council_tax/NORTH_WEST/C": "voa.council_tax_stock.band_c", + "voa/council_tax/NORTH_WEST/D": "voa.council_tax_stock.band_d", + "voa/council_tax/NORTH_WEST/E": "voa.council_tax_stock.band_e", + "voa/council_tax/NORTH_WEST/F": "voa.council_tax_stock.band_f", + "voa/council_tax/NORTH_WEST/G": "voa.council_tax_stock.band_g", + "voa/council_tax/NORTH_WEST/H": "voa.council_tax_stock.band_h", + "voa/council_tax/NORTH_WEST/total": "voa.council_tax_stock.total", + "voa/council_tax/SCOTLAND/A": "scotgov.council_tax_stock.band_a", + "voa/council_tax/SCOTLAND/B": "scotgov.council_tax_stock.band_b", + "voa/council_tax/SCOTLAND/C": "scotgov.council_tax_stock.band_c", + "voa/council_tax/SCOTLAND/D": "scotgov.council_tax_stock.band_d", + "voa/council_tax/SCOTLAND/E": "scotgov.council_tax_stock.band_e", + "voa/council_tax/SCOTLAND/F": "scotgov.council_tax_stock.band_f", + "voa/council_tax/SCOTLAND/G": "scotgov.council_tax_stock.band_g", + "voa/council_tax/SCOTLAND/H": "scotgov.council_tax_stock.band_h", + "voa/council_tax/SCOTLAND/total": "scotgov.council_tax_stock.total", + "voa/council_tax/SOUTH_EAST/A": "voa.council_tax_stock.band_a", + "voa/council_tax/SOUTH_EAST/B": "voa.council_tax_stock.band_b", + "voa/council_tax/SOUTH_EAST/C": "voa.council_tax_stock.band_c", + "voa/council_tax/SOUTH_EAST/D": "voa.council_tax_stock.band_d", + "voa/council_tax/SOUTH_EAST/E": "voa.council_tax_stock.band_e", + "voa/council_tax/SOUTH_EAST/F": "voa.council_tax_stock.band_f", + "voa/council_tax/SOUTH_EAST/G": "voa.council_tax_stock.band_g", + "voa/council_tax/SOUTH_EAST/H": "voa.council_tax_stock.band_h", + "voa/council_tax/SOUTH_EAST/total": "voa.council_tax_stock.total", + "voa/council_tax/SOUTH_WEST/A": "voa.council_tax_stock.band_a", + "voa/council_tax/SOUTH_WEST/B": "voa.council_tax_stock.band_b", + "voa/council_tax/SOUTH_WEST/C": "voa.council_tax_stock.band_c", + "voa/council_tax/SOUTH_WEST/D": "voa.council_tax_stock.band_d", + "voa/council_tax/SOUTH_WEST/E": "voa.council_tax_stock.band_e", + "voa/council_tax/SOUTH_WEST/F": "voa.council_tax_stock.band_f", + "voa/council_tax/SOUTH_WEST/G": "voa.council_tax_stock.band_g", + "voa/council_tax/SOUTH_WEST/H": "voa.council_tax_stock.band_h", + "voa/council_tax/SOUTH_WEST/total": "voa.council_tax_stock.total", + "voa/council_tax/WALES/A": "voa.council_tax_stock.band_a", + "voa/council_tax/WALES/B": "voa.council_tax_stock.band_b", + "voa/council_tax/WALES/C": "voa.council_tax_stock.band_c", + "voa/council_tax/WALES/D": "voa.council_tax_stock.band_d", + "voa/council_tax/WALES/E": "voa.council_tax_stock.band_e", + "voa/council_tax/WALES/F": "voa.council_tax_stock.band_f", + "voa/council_tax/WALES/G": "voa.council_tax_stock.band_g", + "voa/council_tax/WALES/H": "voa.council_tax_stock.band_h", + "voa/council_tax/WALES/total": "voa.council_tax_stock.total", + "voa/council_tax/WEST_MIDLANDS/A": "voa.council_tax_stock.band_a", + "voa/council_tax/WEST_MIDLANDS/B": "voa.council_tax_stock.band_b", + "voa/council_tax/WEST_MIDLANDS/C": "voa.council_tax_stock.band_c", + "voa/council_tax/WEST_MIDLANDS/D": "voa.council_tax_stock.band_d", + "voa/council_tax/WEST_MIDLANDS/E": "voa.council_tax_stock.band_e", + "voa/council_tax/WEST_MIDLANDS/F": "voa.council_tax_stock.band_f", + "voa/council_tax/WEST_MIDLANDS/G": "voa.council_tax_stock.band_g", + "voa/council_tax/WEST_MIDLANDS/H": "voa.council_tax_stock.band_h", + "voa/council_tax/WEST_MIDLANDS/total": "voa.council_tax_stock.total", + "voa/council_tax/YORKSHIRE/A": "voa.council_tax_stock.band_a", + "voa/council_tax/YORKSHIRE/B": "voa.council_tax_stock.band_b", + "voa/council_tax/YORKSHIRE/C": "voa.council_tax_stock.band_c", + "voa/council_tax/YORKSHIRE/D": "voa.council_tax_stock.band_d", + "voa/council_tax/YORKSHIRE/E": "voa.council_tax_stock.band_e", + "voa/council_tax/YORKSHIRE/F": "voa.council_tax_stock.band_f", + "voa/council_tax/YORKSHIRE/G": "voa.council_tax_stock.band_g", + "voa/council_tax/YORKSHIRE/H": "voa.council_tax_stock.band_h", + "voa/council_tax/YORKSHIRE/total": "voa.council_tax_stock.total" + }, + "excluded": { + "dwp/benefit_cap_total_reduction": "The GBP 320.9m total reduction is uk-data's computed annualization of a monthly figure - excluded per the facts-only ADR (#139).", + "hmrc/capital_gains_band_100000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", + "hmrc/capital_gains_band_1000000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", + "hmrc/capital_gains_band_12300": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", + "hmrc/capital_gains_band_2000000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", + "hmrc/capital_gains_band_25000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", + "hmrc/capital_gains_band_250000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", + "hmrc/capital_gains_band_50000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", + "hmrc/capital_gains_band_500000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", + "hmrc/capital_gains_band_5000000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", + "hmrc/cgt_taxpayers_band_100000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", + "hmrc/cgt_taxpayers_band_1000000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", + "hmrc/cgt_taxpayers_band_12300": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", + "hmrc/cgt_taxpayers_band_2000000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", + "hmrc/cgt_taxpayers_band_25000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", + "hmrc/cgt_taxpayers_band_250000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", + "hmrc/cgt_taxpayers_band_50000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", + "hmrc/cgt_taxpayers_band_500000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", + "hmrc/cgt_taxpayers_band_5000000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", + "hmrc/salary_sacrifice_contributions": "SPP Review 2025 base value (GBP 24bn); the pinned asset 404s with no Wayback snapshot - blocked until a source surfaces (checklist row).", + "housing/rent_private": "Computed rate x count products (PIPR mean rent / EHS mean weekly cost x unpinned tenure counts). The base facts are ported (#159); the product stays a populace-side declaration per the facts-only ADR.", + "housing/rent_social": "Computed rate x count products (PIPR mean rent / EHS mean weekly cost x unpinned tenure counts). The base facts are ported (#159); the product stays a populace-side declaration per the facts-only ADR.", + "housing/total_mortgage": "No publisher source: uk-data cites the ONS rent bulletin, which carries no mortgage figure (policyengine-uk-data#453). Nearest sourced anchor is EHS AT1.7 all-mortgagors mean weekly housing costs.", + "nts/households_no_vehicle": "DfT NTS facts are percent shares; uk-data targets household counts. Identity-only value resolution cannot scale a share into a count - populace derives the count targets (share x household total), following the US derived-CHIP precedent.", + "nts/households_one_vehicle": "DfT NTS facts are percent shares; uk-data targets household counts. Identity-only value resolution cannot scale a share into a count - populace derives the count targets (share x household total), following the US derived-CHIP precedent.", + "nts/households_two_plus_vehicles": "DfT NTS facts are percent shares; uk-data targets household counts. Identity-only value resolution cannot scale a share into a count - populace derives the count targets (share x household total), following the US derived-CHIP precedent.", + "ons/household_land_value/EAST_MIDLANDS": "Regional household land values are uk-data's computed allocation (dwellings x average house price shares, sources/mhclg_regional_land.py) - no publisher regional land facts exist to port.", + "ons/household_land_value/EAST_OF_ENGLAND": "Regional household land values are uk-data's computed allocation (dwellings x average house price shares, sources/mhclg_regional_land.py) - no publisher regional land facts exist to port.", + "ons/household_land_value/LONDON": "Regional household land values are uk-data's computed allocation (dwellings x average house price shares, sources/mhclg_regional_land.py) - no publisher regional land facts exist to port.", + "ons/household_land_value/NORTH_EAST": "Regional household land values are uk-data's computed allocation (dwellings x average house price shares, sources/mhclg_regional_land.py) - no publisher regional land facts exist to port.", + "ons/household_land_value/NORTH_WEST": "Regional household land values are uk-data's computed allocation (dwellings x average house price shares, sources/mhclg_regional_land.py) - no publisher regional land facts exist to port.", + "ons/household_land_value/SCOTLAND": "Regional household land values are uk-data's computed allocation (dwellings x average house price shares, sources/mhclg_regional_land.py) - no publisher regional land facts exist to port.", + "ons/household_land_value/SOUTH_EAST": "Regional household land values are uk-data's computed allocation (dwellings x average house price shares, sources/mhclg_regional_land.py) - no publisher regional land facts exist to port.", + "ons/household_land_value/SOUTH_WEST": "Regional household land values are uk-data's computed allocation (dwellings x average house price shares, sources/mhclg_regional_land.py) - no publisher regional land facts exist to port.", + "ons/household_land_value/WALES": "Regional household land values are uk-data's computed allocation (dwellings x average house price shares, sources/mhclg_regional_land.py) - no publisher regional land facts exist to port.", + "ons/household_land_value/WEST_MIDLANDS": "Regional household land values are uk-data's computed allocation (dwellings x average house price shares, sources/mhclg_regional_land.py) - no publisher regional land facts exist to port.", + "ons/household_land_value/YORKSHIRE": "Regional household land values are uk-data's computed allocation (dwellings x average house price shares, sources/mhclg_regional_land.py) - no publisher regional land facts exist to port.", + "ons/tenure_england_owned_outright": "England tenure counts come from an LA-grain workbook uk-data code-sums; ruled non-portable as national facts on #133 - moved to the wave-3 LA package (#134).", + "ons/tenure_england_owned_with_mortgage": "England tenure counts come from an LA-grain workbook uk-data code-sums; ruled non-portable as national facts on #133 - moved to the wave-3 LA package (#134).", + "ons/tenure_england_rented_privately": "England tenure counts come from an LA-grain workbook uk-data code-sums; ruled non-portable as national facts on #133 - moved to the wave-3 LA package (#134).", + "ons/tenure_england_social_rent": "England tenure counts come from an LA-grain workbook uk-data code-sums; ruled non-portable as national facts on #133 - moved to the wave-3 LA package (#134).", + "ons/tenure_england_total": "England tenure counts come from an LA-grain workbook uk-data code-sums; ruled non-portable as national facts on #133 - moved to the wave-3 LA package (#134)." + } + }, + "targets": [ + { + "target_id": "obr.income_tax", + "family": "obr", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "concept": "uk.tax.income_tax.amount", + "map_to": "household" + }, + "bindings": { + "policyengine": { + "metric_name": "obr/income_tax", + "value_variable": "income_tax", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "obr/income_tax", + "status": "pending", + "value_rule": "uk.tax.income_tax.amount" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "obr", + "source_concept": "obr.income_tax" + } + }, + { + "target_id": "obr.ni", + "family": "obr", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "concept": "uk.tax.national_insurance.amount", + "map_to": "household" + }, + "bindings": { + "policyengine": { + "metric_name": "obr/ni", + "value_variable": "ni_employee", + "from_entity": "person", + "map_to": "household", + "notes": "uk-data binds this EFO total-NI line to ni_employee only, while separate employee/employer/self-employed lines are also calibrated - suspected binding defect carried as-is for parity; adjudicate in populace#622." + }, + "axiom": { + "metric_name": "obr/ni", + "status": "pending", + "value_rule": "uk.tax.national_insurance.amount" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "obr", + "source_concept": "obr.ni_total" + } + }, + { + "target_id": "obr.ni_employee", + "family": "obr", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "concept": "uk.tax.ni_employee.amount", + "map_to": "household" + }, + "bindings": { + "policyengine": { + "metric_name": "obr/ni_employee", + "value_variable": "ni_employee", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "obr/ni_employee", + "status": "pending", + "value_rule": "uk.tax.ni_employee.amount" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "obr", + "source_concept": "obr.ni_employee" + } + }, + { + "target_id": "obr.ni_employer", + "family": "obr", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "concept": "uk.tax.ni_employer.amount", + "map_to": "household" + }, + "bindings": { + "policyengine": { + "metric_name": "obr/ni_employer", + "value_variable": "ni_employer", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "obr/ni_employer", + "status": "pending", + "value_rule": "uk.tax.ni_employer.amount" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "obr", + "source_concept": "obr.ni_employer" + } + }, + { + "target_id": "obr.ni_self_employed", + "family": "obr", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "concept": "uk.tax.ni_self_employed.amount", + "map_to": "household" + }, + "bindings": { + "policyengine": { + "metric_name": "obr/ni_self_employed", + "value_variable": "ni_self_employed", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "obr/ni_self_employed", + "status": "pending", + "value_rule": "uk.tax.ni_self_employed.amount" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "obr", + "source_concept": "obr.ni_self_employed" + } + }, + { + "target_id": "obr.vat", + "family": "obr", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.tax.vat.amount" + }, + "bindings": { + "policyengine": { + "metric_name": "obr/vat", + "value_variable": "vat" + }, + "axiom": { + "metric_name": "obr/vat", + "status": "pending", + "value_rule": "uk.tax.vat.amount" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "obr", + "source_concept": "obr.vat" + } + }, + { + "target_id": "obr.fuel_duties", + "family": "obr", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.tax.fuel_duty.amount" + }, + "bindings": { + "policyengine": { + "metric_name": "obr/fuel_duties", + "value_variable": "fuel_duty" + }, + "axiom": { + "metric_name": "obr/fuel_duties", + "status": "pending", + "value_rule": "uk.tax.fuel_duty.amount" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "obr", + "source_concept": "obr.fuel_duties" + } + }, + { + "target_id": "obr.capital_gains_tax", + "family": "obr", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "concept": "uk.tax.capital_gains_tax.amount", + "map_to": "household" + }, + "bindings": { + "policyengine": { + "metric_name": "obr/capital_gains_tax", + "value_variable": "capital_gains_tax", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "obr/capital_gains_tax", + "status": "pending", + "value_rule": "uk.tax.capital_gains_tax.amount" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "obr", + "source_concept": "obr.capital_gains_tax" + } + }, + { + "target_id": "obr.sdlt", + "family": "obr", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.tax.stamp_duty_land_tax.amount" + }, + "bindings": { + "policyengine": { + "metric_name": "obr/sdlt", + "value_variable": "stamp_duty_land_tax" + }, + "axiom": { + "metric_name": "obr/sdlt", + "status": "pending", + "value_rule": "uk.tax.stamp_duty_land_tax.amount" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "obr", + "source_concept": "obr.sdlt" + } + }, + { + "target_id": "obr.attendance_allowance", + "family": "obr", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "concept": "uk.benefits.attendance_allowance.amount", + "map_to": "household" + }, + "bindings": { + "policyengine": { + "metric_name": "obr/attendance_allowance", + "value_variable": "attendance_allowance", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "obr/attendance_allowance", + "status": "pending", + "value_rule": "uk.benefits.attendance_allowance.amount" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "obr", + "source_concept": "obr.attendance_allowance" + } + }, + { + "target_id": "obr.carers_allowance", + "family": "obr", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "concept": "uk.benefits.carers_allowance.amount", + "map_to": "household" + }, + "bindings": { + "policyengine": { + "metric_name": "obr/carers_allowance", + "value_variable": "carers_allowance", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "obr/carers_allowance", + "status": "pending", + "value_rule": "uk.benefits.carers_allowance.amount" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "obr", + "source_concept": "obr.carers_allowance" + } + }, + { + "target_id": "obr.child_benefit", + "family": "obr", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "benunit", + "concept": "uk.benefits.child_benefit.amount", + "map_to": "household" + }, + "bindings": { + "policyengine": { + "metric_name": "obr/child_benefit", + "value_variable": "child_benefit", + "from_entity": "benunit", + "map_to": "household" + }, + "axiom": { + "metric_name": "obr/child_benefit", + "status": "pending", + "value_rule": "uk.benefits.child_benefit.amount" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "obr", + "source_concept": "obr.child_benefit" + } + }, + { + "target_id": "obr.council_tax", + "family": "obr", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.tax.council_tax.net_amount" + }, + "bindings": { + "policyengine": { + "metric_name": "obr/council_tax", + "value_variable": "council_tax_less_benefit", + "notes": "OBR Table 4.1 reports net council tax receipts (net of council tax reduction), so the binding is council_tax_less_benefit, not gross council_tax (compute/council_tax.py:21-43)." + }, + "axiom": { + "metric_name": "obr/council_tax", + "status": "pending", + "value_rule": "uk.tax.council_tax.net_amount" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "obr", + "source_concept": "obr.council_tax_total" + } + }, + { + "target_id": "obr.council_tax_england", + "family": "obr", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.tax.council_tax.net_amount", + "filters": [ + { + "concept": "uk.geography.country", + "equals": "england" + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "obr/council_tax_england", + "value_variable": "council_tax_less_benefit", + "filters": [ + { + "variable": "country", + "equals": "ENGLAND" + } + ], + "notes": "OBR Table 4.1 reports net council tax receipts (net of council tax reduction), so the binding is council_tax_less_benefit, not gross council_tax (compute/council_tax.py:21-43)." + }, + "axiom": { + "metric_name": "obr/council_tax_england", + "status": "pending", + "value_rule": "uk.tax.council_tax.net_amount" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "obr", + "source_concept": "obr.council_tax_england" + } + }, + { + "target_id": "obr.council_tax_scotland", + "family": "obr", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.tax.council_tax.net_amount", + "filters": [ + { + "concept": "uk.geography.country", + "equals": "scotland" + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "obr/council_tax_scotland", + "value_variable": "council_tax_less_benefit", + "filters": [ + { + "variable": "country", + "equals": "SCOTLAND" + } + ], + "notes": "OBR Table 4.1 reports net council tax receipts (net of council tax reduction), so the binding is council_tax_less_benefit, not gross council_tax (compute/council_tax.py:21-43)." + }, + "axiom": { + "metric_name": "obr/council_tax_scotland", + "status": "pending", + "value_rule": "uk.tax.council_tax.net_amount" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "obr", + "source_concept": "obr.council_tax_scotland" + } + }, + { + "target_id": "obr.council_tax_wales", + "family": "obr", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.tax.council_tax.net_amount", + "filters": [ + { + "concept": "uk.geography.country", + "equals": "wales" + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "obr/council_tax_wales", + "value_variable": "council_tax_less_benefit", + "filters": [ + { + "variable": "country", + "equals": "WALES" + } + ], + "notes": "OBR Table 4.1 reports net council tax receipts (net of council tax reduction), so the binding is council_tax_less_benefit, not gross council_tax (compute/council_tax.py:21-43)." + }, + "axiom": { + "metric_name": "obr/council_tax_wales", + "status": "pending", + "value_rule": "uk.tax.council_tax.net_amount" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "obr", + "source_concept": "obr.council_tax_wales" + } + }, + { + "target_id": "obr.domestic_rates", + "family": "obr", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.tax.domestic_rates.amount" + }, + "bindings": { + "policyengine": { + "metric_name": "obr/domestic_rates", + "value_variable": "domestic_rates" + }, + "axiom": { + "metric_name": "obr/domestic_rates", + "status": "pending", + "value_rule": "uk.tax.domestic_rates.amount" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "obr", + "source_concept": "obr.domestic_rates" + } + }, + { + "target_id": "obr.esa", + "family": "obr", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.benefits.esa.amount" + }, + "bindings": { + "policyengine": { + "metric_name": "obr/esa", + "value_expression": "esa_income + esa_contrib", + "map_to": "household", + "notes": "EFO incapacity-benefits line; uk-data sums benunit-level esa_income and person-level esa_contrib to household (compute/income.py:98-102)." + }, + "axiom": { + "metric_name": "obr/esa", + "status": "pending", + "value_rule": "uk.benefits.esa.amount" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "obr", + "source_concept": "obr.incapacity_benefits" + } + }, + { + "target_id": "obr.housing_benefit", + "family": "obr", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "benunit", + "concept": "uk.benefits.housing_benefit.amount", + "map_to": "household" + }, + "bindings": { + "policyengine": { + "metric_name": "obr/housing_benefit", + "value_variable": "housing_benefit", + "from_entity": "benunit", + "map_to": "household" + }, + "axiom": { + "metric_name": "obr/housing_benefit", + "status": "pending", + "value_rule": "uk.benefits.housing_benefit.amount" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "obr", + "source_concept": "obr.housing_benefit" + } + }, + { + "target_id": "obr.jobseekers_allowance", + "family": "obr", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "benunit", + "concept": "uk.benefits.jsa.amount", + "map_to": "household" + }, + "bindings": { + "policyengine": { + "metric_name": "obr/jobseekers_allowance", + "value_variable": "jsa", + "from_entity": "benunit", + "map_to": "household" + }, + "axiom": { + "metric_name": "obr/jobseekers_allowance", + "status": "pending", + "value_rule": "uk.benefits.jsa.amount" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "obr", + "source_concept": "obr.jobseekers_allowance" + } + }, + { + "target_id": "obr.pension_credit", + "family": "obr", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "benunit", + "concept": "uk.benefits.pension_credit.amount", + "map_to": "household" + }, + "bindings": { + "policyengine": { + "metric_name": "obr/pension_credit", + "value_variable": "pension_credit", + "from_entity": "benunit", + "map_to": "household" + }, + "axiom": { + "metric_name": "obr/pension_credit", + "status": "pending", + "value_rule": "uk.benefits.pension_credit.amount" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "obr", + "source_concept": "obr.pension_credit" + } + }, + { + "target_id": "obr.pip", + "family": "obr", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "concept": "uk.benefits.disability_benefits.amount", + "map_to": "household" + }, + "bindings": { + "policyengine": { + "metric_name": "obr/pip", + "value_variable": "pip", + "from_entity": "person", + "map_to": "household", + "notes": "EFO line covers DLA and PIP combined; uk-data binds pip only - carried as-is for parity; adjudicate in populace#622." + }, + "axiom": { + "metric_name": "obr/pip", + "status": "pending", + "value_rule": "uk.benefits.disability_benefits.amount" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "obr", + "source_concept": "obr.dla_and_pip" + } + }, + { + "target_id": "obr.state_pension", + "family": "obr", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "concept": "uk.benefits.state_pension.amount", + "map_to": "household" + }, + "bindings": { + "policyengine": { + "metric_name": "obr/state_pension", + "value_variable": "state_pension", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "obr/state_pension", + "status": "pending", + "value_rule": "uk.benefits.state_pension.amount" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "obr", + "source_concept": "obr.state_pension" + } + }, + { + "target_id": "obr.statutory_maternity_pay", + "family": "obr", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "concept": "uk.benefits.statutory_maternity_pay.amount", + "map_to": "household" + }, + "bindings": { + "policyengine": { + "metric_name": "obr/statutory_maternity_pay", + "value_variable": "statutory_maternity_pay", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "obr/statutory_maternity_pay", + "status": "pending", + "value_rule": "uk.benefits.statutory_maternity_pay.amount" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "obr", + "source_concept": "obr.statutory_maternity_pay" + } + }, + { + "target_id": "obr.tv_licence_fee", + "family": "obr", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.tax.tv_licence.amount" + }, + "bindings": { + "policyengine": { + "metric_name": "obr/tv_licence_fee", + "value_variable": "tv_licence" + }, + "axiom": { + "metric_name": "obr/tv_licence_fee", + "status": "pending", + "value_rule": "uk.tax.tv_licence.amount" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "obr", + "source_concept": "obr.tv_licence_fee" + } + }, + { + "target_id": "obr.universal_credit_in_cap", + "family": "obr", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "benunit", + "concept": "uk.benefits.universal_credit.amount", + "map_to": "household", + "filters": [ + { + "concept": "uk.benefits.benefit_cap.reduction", + "operator": ">", + "value": 0 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "obr/universal_credit_in_cap", + "value_variable": "universal_credit", + "from_entity": "benunit", + "map_to": "household", + "filters": [ + { + "variable": "benefit_cap_reduction", + "operator": ">", + "value": 0 + } + ], + "notes": "Split of UC spend by benefit-cap status (compute/benefits.py:119-127)." + }, + "axiom": { + "metric_name": "obr/universal_credit_in_cap", + "status": "pending", + "value_rule": "uk.benefits.universal_credit.amount" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "obr", + "source_concept": "obr.universal_credit_in_cap" + } + }, + { + "target_id": "obr.universal_credit_outside_cap", + "family": "obr", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "benunit", + "concept": "uk.benefits.universal_credit.amount", + "map_to": "household", + "filters": [ + { + "concept": "uk.benefits.benefit_cap.reduction", + "operator": "==", + "value": 0 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "obr/universal_credit_outside_cap", + "value_variable": "universal_credit", + "from_entity": "benunit", + "map_to": "household", + "filters": [ + { + "variable": "benefit_cap_reduction", + "operator": "==", + "value": 0 + } + ], + "notes": "Split of UC spend by benefit-cap status (compute/benefits.py:119-127)." + }, + "axiom": { + "metric_name": "obr/universal_credit_outside_cap", + "status": "pending", + "value_rule": "uk.benefits.universal_credit.amount" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "obr", + "source_concept": "obr.universal_credit_outside_cap" + } + }, + { + "target_id": "obr.winter_fuel_allowance", + "family": "obr", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.benefits.winter_fuel_payment.amount" + }, + "bindings": { + "policyengine": { + "metric_name": "obr/winter_fuel_allowance", + "value_variable": "winter_fuel_allowance" + }, + "axiom": { + "metric_name": "obr/winter_fuel_allowance", + "status": "pending", + "value_rule": "uk.benefits.winter_fuel_payment.amount" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "obr", + "source_concept": "obr.winter_fuel_payment" + } + }, + { + "target_id": "isc.private_school_students", + "family": "isc", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.education.attends_private_school", + "equals": true + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "obr/private_school_students", + "filters": [ + { + "variable": "attends_private_school", + "equals": true + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "obr/private_school_students", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "isc", + "source_concept": "isc.pupils_at_member_schools" + } + }, + { + "target_id": "hmrc.salary_sacrifice.it_relief_basic_rate", + "family": "hmrc_salary_sacrifice", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.tax.salary_sacrifice.income_tax_relief" + }, + "bindings": { + "policyengine": { + "metric_name": "hmrc/salary_sacrifice_it_relief_basic_rate", + "kind": "input_substitution_counterfactual", + "zeroed_input": "pension_contributions_via_salary_sacrifice", + "folded_into": "employment_income", + "output_delta": "counterfactual_minus_baseline", + "output_variable": "income_tax", + "band": { + "variable": "adjusted_net_income", + "under": "counterfactual", + "above_parameter": "gov.hmrc.income_tax.rates.uk[0].threshold", + "at_or_below_parameter": "gov.hmrc.income_tax.rates.uk[1].threshold" + }, + "from_entity": "person", + "map_to": "household", + "notes": "Income-tax relief attributed to salary sacrifice, banded on counterfactual adjusted net income against the live parameter thresholds (compute/income.py:23-50)." + }, + "axiom": { + "metric_name": "hmrc/salary_sacrifice_it_relief_basic_rate", + "status": "pending", + "value_rule": "uk.tax.salary_sacrifice.income_tax_relief" + } + }, + "ledger_selector": { + "source_name": "hmrc", + "source_concept": "hmrc.ss_income_tax_relief_basic_rate" + } + }, + { + "target_id": "hmrc.salary_sacrifice.it_relief_higher_rate", + "family": "hmrc_salary_sacrifice", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.tax.salary_sacrifice.income_tax_relief" + }, + "bindings": { + "policyengine": { + "metric_name": "hmrc/salary_sacrifice_it_relief_higher_rate", + "kind": "input_substitution_counterfactual", + "zeroed_input": "pension_contributions_via_salary_sacrifice", + "folded_into": "employment_income", + "output_delta": "counterfactual_minus_baseline", + "output_variable": "income_tax", + "band": { + "variable": "adjusted_net_income", + "under": "counterfactual", + "above_parameter": "gov.hmrc.income_tax.rates.uk[1].threshold", + "at_or_below_parameter": "gov.hmrc.income_tax.rates.uk[2].threshold" + }, + "from_entity": "person", + "map_to": "household", + "notes": "Income-tax relief attributed to salary sacrifice, banded on counterfactual adjusted net income against the live parameter thresholds (compute/income.py:23-50)." + }, + "axiom": { + "metric_name": "hmrc/salary_sacrifice_it_relief_higher_rate", + "status": "pending", + "value_rule": "uk.tax.salary_sacrifice.income_tax_relief" + } + }, + "ledger_selector": { + "source_name": "hmrc", + "source_concept": "hmrc.ss_income_tax_relief_higher_rate" + } + }, + { + "target_id": "hmrc.salary_sacrifice.it_relief_additional_rate", + "family": "hmrc_salary_sacrifice", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.tax.salary_sacrifice.income_tax_relief" + }, + "bindings": { + "policyengine": { + "metric_name": "hmrc/salary_sacrifice_it_relief_additional_rate", + "kind": "input_substitution_counterfactual", + "zeroed_input": "pension_contributions_via_salary_sacrifice", + "folded_into": "employment_income", + "output_delta": "counterfactual_minus_baseline", + "output_variable": "income_tax", + "band": { + "variable": "adjusted_net_income", + "under": "counterfactual", + "above_parameter": "gov.hmrc.income_tax.rates.uk[2].threshold" + }, + "from_entity": "person", + "map_to": "household", + "notes": "Income-tax relief attributed to salary sacrifice, banded on counterfactual adjusted net income against the live parameter thresholds (compute/income.py:23-50)." + }, + "axiom": { + "metric_name": "hmrc/salary_sacrifice_it_relief_additional_rate", + "status": "pending", + "value_rule": "uk.tax.salary_sacrifice.income_tax_relief" + } + }, + "ledger_selector": { + "source_name": "hmrc", + "source_concept": "hmrc.ss_income_tax_relief_additional_rate" + } + }, + { + "target_id": "hmrc.salary_sacrifice.nics_relief_employee", + "family": "hmrc_salary_sacrifice", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.tax.salary_sacrifice.employee_nics_relief" + }, + "bindings": { + "policyengine": { + "metric_name": "hmrc/salary_sacrifice_employee_nics_relief", + "kind": "input_substitution_counterfactual", + "zeroed_input": "pension_contributions_via_salary_sacrifice", + "folded_into": "employment_income", + "output_delta": "counterfactual_minus_baseline", + "output_variable": "ni_employee", + "from_entity": "person", + "map_to": "household", + "notes": "NICs relief attributed to salary sacrifice (compute/income.py:59-68). uk-data's SPP-Review-based obr/salary_sacrifice_employee_ni_relief row (source lost) retires onto this hmrc-backed fact - vintage difference for the populace#622 parity gate." + }, + "axiom": { + "metric_name": "hmrc/salary_sacrifice_employee_nics_relief", + "status": "pending", + "value_rule": "uk.tax.salary_sacrifice.employee_nics_relief" + } + }, + "ledger_selector": { + "source_name": "hmrc", + "source_concept": "hmrc.ss_nics_relief_employee" + } + }, + { + "target_id": "hmrc.salary_sacrifice.nics_relief_employer", + "family": "hmrc_salary_sacrifice", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.tax.salary_sacrifice.employer_nics_relief" + }, + "bindings": { + "policyengine": { + "metric_name": "hmrc/salary_sacrifice_employer_nics_relief", + "kind": "input_substitution_counterfactual", + "zeroed_input": "pension_contributions_via_salary_sacrifice", + "folded_into": "employment_income", + "output_delta": "counterfactual_minus_baseline", + "output_variable": "ni_employer", + "from_entity": "person", + "map_to": "household", + "notes": "NICs relief attributed to salary sacrifice (compute/income.py:59-68). uk-data's SPP-Review-based obr/salary_sacrifice_employer_ni_relief row (source lost) retires onto this hmrc-backed fact - vintage difference for the populace#622 parity gate." + }, + "axiom": { + "metric_name": "hmrc/salary_sacrifice_employer_nics_relief", + "status": "pending", + "value_rule": "uk.tax.salary_sacrifice.employer_nics_relief" + } + }, + "ledger_selector": { + "source_name": "hmrc", + "source_concept": "hmrc.ss_nics_relief_employer" + } + }, + { + "target_id": "hmrc.salary_sacrifice.users_total", + "family": "hmrc_salary_sacrifice", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count" + }, + "bindings": { + "policyengine": { + "metric_name": "obr/salary_sacrifice_users_total", + "filters": [ + { + "variable": "pension_contributions_via_salary_sacrifice", + "operator": ">", + "value": 0 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household", + "threshold_price_base_year": 2023, + "notes": "The GBP 2,000 cap is defined at FRS base-year (2023) prices; deflate salary-sacrifice amounts before banding (compute/income.py:71-95)." + }, + "axiom": { + "metric_name": "obr/salary_sacrifice_users_total", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "hmrc", + "source_concept": "hmrc.salary_sacrifice_pension_users", + "dimension_values": { + "salary_sacrifice_threshold_position": "all" + } + } + }, + { + "target_id": "hmrc.salary_sacrifice.users_below_cap", + "family": "hmrc_salary_sacrifice", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count" + }, + "bindings": { + "policyengine": { + "metric_name": "obr/salary_sacrifice_users_below_cap", + "filters": [ + { + "variable": "pension_contributions_via_salary_sacrifice", + "operator": ">", + "value": 0 + }, + { + "variable": "pension_contributions_via_salary_sacrifice", + "operator": "<=", + "value": 2000 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household", + "threshold_price_base_year": 2023, + "notes": "The GBP 2,000 cap is defined at FRS base-year (2023) prices; deflate salary-sacrifice amounts before banding (compute/income.py:71-95)." + }, + "axiom": { + "metric_name": "obr/salary_sacrifice_users_below_cap", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "hmrc", + "source_concept": "hmrc.salary_sacrifice_pension_users", + "dimension_values": { + "salary_sacrifice_threshold_position": "within_2000" + } + } + }, + { + "target_id": "hmrc.salary_sacrifice.users_above_cap", + "family": "hmrc_salary_sacrifice", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count" + }, + "bindings": { + "policyengine": { + "metric_name": "obr/salary_sacrifice_users_above_cap", + "filters": [ + { + "variable": "pension_contributions_via_salary_sacrifice", + "operator": ">", + "value": 2000 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household", + "threshold_price_base_year": 2023, + "notes": "The GBP 2,000 cap is defined at FRS base-year (2023) prices; deflate salary-sacrifice amounts before banding (compute/income.py:71-95)." + }, + "axiom": { + "metric_name": "obr/salary_sacrifice_users_above_cap", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "hmrc", + "source_concept": "hmrc.salary_sacrifice_pension_users", + "dimension_values": { + "salary_sacrifice_threshold_position": "above_2000" + } + } + }, + { + "target_id": "hmrc.spi.employment_income.amount_by_total_income_band", + "family": "hmrc_spi", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.income.employment.amount", + "groupby_dimension": "hmrc.total_income_band" + }, + "bindings": { + "policyengine": { + "metric_name": "hmrc/employment_income_income_band", + "value_variable": "employment_income", + "from_entity": "person", + "map_to": "household", + "groupby_variable": "total_income", + "notes": "Banded by person-level total income; band edges come from the fact dimension (compute/income.py:8-20)." + }, + "axiom": { + "metric_name": "hmrc/employment_income_income_band", + "status": "pending", + "value_rule": "uk.income.employment.amount" + } + }, + "ledger_selector": { + "source_name": "hmrc", + "source_concept": "hmrc.spi_employment_income_amount", + "groupby_dimension": "hmrc.total_income_band" + } + }, + { + "target_id": "hmrc.spi.employment_income.count_by_total_income_band", + "family": "hmrc_spi", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "groupby_dimension": "hmrc.total_income_band", + "filters": [ + { + "concept": "uk.income.employment.amount", + "operator": ">", + "value": 0 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "hmrc/employment_income_count_income_band", + "groupby_variable": "total_income", + "filters": [ + { + "variable": "employment_income", + "operator": ">", + "value": 0 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "hmrc/employment_income_count_income_band", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "hmrc", + "source_concept": "hmrc.spi_employment_income_count", + "groupby_dimension": "hmrc.total_income_band" + } + }, + { + "target_id": "hmrc.spi.self_employment_income.amount_by_total_income_band", + "family": "hmrc_spi", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.income.self_employment.amount", + "groupby_dimension": "hmrc.total_income_band" + }, + "bindings": { + "policyengine": { + "metric_name": "hmrc/self_employment_income_income_band", + "value_variable": "self_employment_income", + "from_entity": "person", + "map_to": "household", + "groupby_variable": "total_income", + "notes": "Banded by person-level total income; band edges come from the fact dimension (compute/income.py:8-20)." + }, + "axiom": { + "metric_name": "hmrc/self_employment_income_income_band", + "status": "pending", + "value_rule": "uk.income.self_employment.amount" + } + }, + "ledger_selector": { + "source_name": "hmrc", + "source_concept": "hmrc.spi_self_employment_income_amount", + "groupby_dimension": "hmrc.total_income_band" + } + }, + { + "target_id": "hmrc.spi.self_employment_income.count_by_total_income_band", + "family": "hmrc_spi", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "groupby_dimension": "hmrc.total_income_band", + "filters": [ + { + "concept": "uk.income.self_employment.amount", + "operator": ">", + "value": 0 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "hmrc/self_employment_income_count_income_band", + "groupby_variable": "total_income", + "filters": [ + { + "variable": "self_employment_income", + "operator": ">", + "value": 0 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "hmrc/self_employment_income_count_income_band", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "hmrc", + "source_concept": "hmrc.spi_self_employment_income_count", + "groupby_dimension": "hmrc.total_income_band" + } + }, + { + "target_id": "hmrc.spi.dividend_income.amount_by_total_income_band", + "family": "hmrc_spi", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.income.dividends.amount", + "groupby_dimension": "hmrc.total_income_band" + }, + "bindings": { + "policyengine": { + "metric_name": "hmrc/dividend_income_income_band", + "value_variable": "dividend_income", + "from_entity": "person", + "map_to": "household", + "groupby_variable": "total_income", + "notes": "Banded by person-level total income; band edges come from the fact dimension (compute/income.py:8-20)." + }, + "axiom": { + "metric_name": "hmrc/dividend_income_income_band", + "status": "pending", + "value_rule": "uk.income.dividends.amount" + } + }, + "ledger_selector": { + "source_name": "hmrc", + "source_concept": "hmrc.spi_dividend_income_amount", + "groupby_dimension": "hmrc.total_income_band" + } + }, + { + "target_id": "hmrc.spi.dividend_income.count_by_total_income_band", + "family": "hmrc_spi", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "groupby_dimension": "hmrc.total_income_band", + "filters": [ + { + "concept": "uk.income.dividends.amount", + "operator": ">", + "value": 0 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "hmrc/dividend_income_count_income_band", + "groupby_variable": "total_income", + "filters": [ + { + "variable": "dividend_income", + "operator": ">", + "value": 0 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "hmrc/dividend_income_count_income_band", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "hmrc", + "source_concept": "hmrc.spi_dividend_income_count", + "groupby_dimension": "hmrc.total_income_band" + } + }, + { + "target_id": "hmrc.spi.property_income.amount_by_total_income_band", + "family": "hmrc_spi", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.income.property.amount", + "groupby_dimension": "hmrc.total_income_band" + }, + "bindings": { + "policyengine": { + "metric_name": "hmrc/property_income_income_band", + "value_variable": "property_income", + "from_entity": "person", + "map_to": "household", + "groupby_variable": "total_income", + "notes": "Banded by person-level total income; band edges come from the fact dimension (compute/income.py:8-20). The x1.9 property-income undercount adjustment is a populace-side value declaration, not a fact property." + }, + "axiom": { + "metric_name": "hmrc/property_income_income_band", + "status": "pending", + "value_rule": "uk.income.property.amount" + } + }, + "ledger_selector": { + "source_name": "hmrc", + "source_concept": "hmrc.spi_property_income_amount", + "groupby_dimension": "hmrc.total_income_band" + } + }, + { + "target_id": "hmrc.spi.property_income.count_by_total_income_band", + "family": "hmrc_spi", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "groupby_dimension": "hmrc.total_income_band", + "filters": [ + { + "concept": "uk.income.property.amount", + "operator": ">", + "value": 0 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "hmrc/property_income_count_income_band", + "groupby_variable": "total_income", + "filters": [ + { + "variable": "property_income", + "operator": ">", + "value": 0 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "hmrc/property_income_count_income_band", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "hmrc", + "source_concept": "hmrc.spi_property_income_count", + "groupby_dimension": "hmrc.total_income_band" + } + }, + { + "target_id": "hmrc.spi.private_pension_income.amount_by_total_income_band", + "family": "hmrc_spi", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.income.private_pension.amount", + "groupby_dimension": "hmrc.total_income_band" + }, + "bindings": { + "policyengine": { + "metric_name": "hmrc/private_pension_income_income_band", + "value_variable": "private_pension_income", + "from_entity": "person", + "map_to": "household", + "groupby_variable": "total_income", + "notes": "Banded by person-level total income; band edges come from the fact dimension (compute/income.py:8-20)." + }, + "axiom": { + "metric_name": "hmrc/private_pension_income_income_band", + "status": "pending", + "value_rule": "uk.income.private_pension.amount" + } + }, + "ledger_selector": { + "source_name": "hmrc", + "source_concept": "hmrc.spi_private_pension_income_amount", + "groupby_dimension": "hmrc.total_income_band" + } + }, + { + "target_id": "hmrc.spi.private_pension_income.count_by_total_income_band", + "family": "hmrc_spi", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "groupby_dimension": "hmrc.total_income_band", + "filters": [ + { + "concept": "uk.income.private_pension.amount", + "operator": ">", + "value": 0 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "hmrc/private_pension_income_count_income_band", + "groupby_variable": "total_income", + "filters": [ + { + "variable": "private_pension_income", + "operator": ">", + "value": 0 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "hmrc/private_pension_income_count_income_band", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "hmrc", + "source_concept": "hmrc.spi_private_pension_income_count", + "groupby_dimension": "hmrc.total_income_band" + } + }, + { + "target_id": "hmrc.spi.state_pension.amount_by_total_income_band", + "family": "hmrc_spi", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.income.state_pension.amount", + "groupby_dimension": "hmrc.total_income_band" + }, + "bindings": { + "policyengine": { + "metric_name": "hmrc/state_pension_income_band", + "value_variable": "state_pension", + "from_entity": "person", + "map_to": "household", + "groupby_variable": "total_income", + "notes": "Banded by person-level total income; band edges come from the fact dimension (compute/income.py:8-20)." + }, + "axiom": { + "metric_name": "hmrc/state_pension_income_band", + "status": "pending", + "value_rule": "uk.income.state_pension.amount" + } + }, + "ledger_selector": { + "source_name": "hmrc", + "source_concept": "hmrc.spi_state_pension_amount", + "groupby_dimension": "hmrc.total_income_band" + } + }, + { + "target_id": "hmrc.spi.state_pension.count_by_total_income_band", + "family": "hmrc_spi", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "groupby_dimension": "hmrc.total_income_band", + "filters": [ + { + "concept": "uk.income.state_pension.amount", + "operator": ">", + "value": 0 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "hmrc/state_pension_count_income_band", + "groupby_variable": "total_income", + "filters": [ + { + "variable": "state_pension", + "operator": ">", + "value": 0 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "hmrc/state_pension_count_income_band", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "hmrc", + "source_concept": "hmrc.spi_state_pension_count", + "groupby_dimension": "hmrc.total_income_band" + } + }, + { + "target_id": "hmrc.cgt.taxpayers_total", + "family": "hmrc_cgt", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.income.capital_gains.amount", + "operator": ">", + "value": "gov.hmrc.cgt.annual_exempt_amount" + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "hmrc/cgt_taxpayers", + "kind": "parameter_gated_threshold", + "gate_parameter": "gov.hmrc.cgt.annual_exempt_amount", + "gated_variable": "capital_gains", + "gate_comparison": ">", + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household", + "notes": "A CGT taxpayer means gains above the annual exempt amount in force that year, read live from the parameter tree - gating only the count (not the amount) would target a mean gain over two different populations (sources/hmrc_cgt.py:1-46)." + }, + "axiom": { + "metric_name": "hmrc/cgt_taxpayers", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "hmrc", + "source_concept": "hmrc.cgt_taxpayers_total" + } + }, + { + "target_id": "hmrc.cgt.gains_total", + "family": "hmrc_cgt", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.income.capital_gains.amount", + "filters": [ + { + "concept": "uk.income.capital_gains.amount", + "operator": ">", + "value": "gov.hmrc.cgt.annual_exempt_amount" + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "hmrc/capital_gains_total", + "kind": "parameter_gated_threshold", + "gate_parameter": "gov.hmrc.cgt.annual_exempt_amount", + "gated_variable": "capital_gains", + "gate_comparison": ">", + "value_variable": "capital_gains", + "from_entity": "person", + "map_to": "household", + "notes": "Gains summed over people whose gains exceed the annual exempt amount (sources/hmrc_cgt.py:86-104). Also the single-homing successor for populace's UK_CGT_TARGET_SPECS (populace#622 item 6)." + }, + "axiom": { + "metric_name": "hmrc/capital_gains_total", + "status": "pending", + "value_rule": "uk.income.capital_gains.amount" + } + }, + "ledger_selector": { + "source_name": "hmrc", + "source_concept": "hmrc.cgt_gains_total" + } + }, + { + "target_id": "dwp.benefit_cap.capped_households", + "family": "dwp_benefit_cap", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count", + "filters": [ + { + "concept": "uk.benefits.benefit_cap.reduction", + "operator": ">", + "value": 0 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/benefit_capped_households", + "reduce": "any", + "household_conditions": [ + { + "variable": "benefit_cap_reduction", + "entity": "benunit", + "reduce": "any", + "operator": ">", + "value": 0 + } + ], + "value_variable": "household_count", + "notes": "0/1 household indicator, not a benunit headcount (compute/benefits.py:14-21). The publisher's GBP 320.9m total-reduction companion is a computed annualization - excluded per the facts-only ADR." + }, + "axiom": { + "metric_name": "dwp/benefit_capped_households", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_capped_households_total" + } + }, + { + "target_id": "dwp.pip.daily_living_standard_claimants", + "family": "dwp_pip", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.benefits.pip.daily_living_category", + "equals": "standard" + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/pip_dl_standard_claimants", + "filters": [ + { + "variable": "pip_dl_category", + "equals": "STANDARD" + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household", + "notes": "True source is DWP FOI2025/24990 (caseload at end January 2025), not the routine PIP publication tables." + }, + "axiom": { + "metric_name": "dwp/pip_dl_standard_claimants", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.pip_daily_living_claimants", + "dimension_values": { + "pip_daily_living_award_rate": "standard" + } + } + }, + { + "target_id": "dwp.pip.daily_living_enhanced_claimants", + "family": "dwp_pip", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.benefits.pip.daily_living_category", + "equals": "enhanced" + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/pip_dl_enhanced_claimants", + "filters": [ + { + "variable": "pip_dl_category", + "equals": "ENHANCED" + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household", + "notes": "True source is DWP FOI2025/24990 (caseload at end January 2025), not the routine PIP publication tables." + }, + "axiom": { + "metric_name": "dwp/pip_dl_enhanced_claimants", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.pip_daily_living_claimants", + "dimension_values": { + "pip_daily_living_award_rate": "enhanced" + } + } + }, + { + "target_id": "dwp.esa_claimants", + "family": "dwp_legacy_benefits", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "benunit", + "map_to": "household", + "concept": "uk.benefit_unit.count" + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/esa_claimants", + "filters": [ + { + "variable": "esa", + "operator": ">", + "value": 0 + } + ], + "value_variable": "benunit_count", + "from_entity": "benunit", + "map_to": "household", + "notes": "uk-data binds the combined count to the benunit-level esa variable." + }, + "axiom": { + "metric_name": "dwp/esa_claimants", + "status": "pending", + "value_rule": "uk.benefit_unit.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.esa_claimants", + "dimension_values": { + "esa_claim_type": "all" + } + } + }, + { + "target_id": "dwp.esa_contrib_claimants", + "family": "dwp_legacy_benefits", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count" + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/esa_contrib_claimants", + "filters": [ + { + "variable": "esa_contrib", + "operator": ">", + "value": 0 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "dwp/esa_contrib_claimants", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.esa_claimants", + "dimension_values": { + "esa_claim_type": "contributions_based" + } + } + }, + { + "target_id": "dwp.esa_income_claimants", + "family": "dwp_legacy_benefits", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "benunit", + "map_to": "household", + "concept": "uk.benefit_unit.count" + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/esa_income_claimants", + "filters": [ + { + "variable": "esa_income", + "operator": ">", + "value": 0 + } + ], + "value_variable": "benunit_count", + "from_entity": "benunit", + "map_to": "household" + }, + "axiom": { + "metric_name": "dwp/esa_income_claimants", + "status": "pending", + "value_rule": "uk.benefit_unit.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.esa_claimants", + "dimension_values": { + "esa_claim_type": "income_related" + } + } + }, + { + "target_id": "dwp.jsa_claimants", + "family": "dwp_legacy_benefits", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count" + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/jsa_claimants", + "filters": [ + { + "variable": "jsa_contrib", + "operator": ">", + "value": 0 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household", + "notes": "uk-data binds the JSA claimant count to contributory JSA only (jsa_contrib) - carried as-is for parity; adjudicate in populace#622." + }, + "axiom": { + "metric_name": "dwp/jsa_claimants", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.jsa_claimants" + } + }, + { + "target_id": "dwp.uc.households_children_1", + "family": "dwp_universal_credit", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count", + "filters": [ + { + "concept": "uk.benefits.universal_credit.amount", + "operator": ">", + "value": 0 + }, + { + "concept": "uk.household.children", + "operator": "==", + "value": 1 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/uc/claimants_with_1_children", + "reduce": "any", + "household_conditions": [ + { + "variable": "universal_credit", + "entity": "benunit", + "reduce": "any", + "operator": ">", + "value": 0 + }, + { + "variable": "is_child", + "entity": "person", + "reduce": "sum", + "operator": "==", + "value": 1 + } + ], + "value_variable": "household_count", + "notes": "Household indicator: any benunit on UC and the household child count matches (compute/benefits.py:33-51)." + }, + "axiom": { + "metric_name": "dwp/uc/claimants_with_1_children", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_households", + "groupby_dimension": "dwp.uc_number_of_children", + "dimension_values": { + "number_of_children": 1 + } + } + }, + { + "target_id": "dwp.uc.households_children_2", + "family": "dwp_universal_credit", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count", + "filters": [ + { + "concept": "uk.benefits.universal_credit.amount", + "operator": ">", + "value": 0 + }, + { + "concept": "uk.household.children", + "operator": "==", + "value": 2 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/uc/claimants_with_2_children", + "reduce": "any", + "household_conditions": [ + { + "variable": "universal_credit", + "entity": "benunit", + "reduce": "any", + "operator": ">", + "value": 0 + }, + { + "variable": "is_child", + "entity": "person", + "reduce": "sum", + "operator": "==", + "value": 2 + } + ], + "value_variable": "household_count", + "notes": "Household indicator: any benunit on UC and the household child count matches (compute/benefits.py:33-51)." + }, + "axiom": { + "metric_name": "dwp/uc/claimants_with_2_children", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_households", + "groupby_dimension": "dwp.uc_number_of_children", + "dimension_values": { + "number_of_children": 2 + } + } + }, + { + "target_id": "dwp.uc.households_children_3", + "family": "dwp_universal_credit", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count", + "filters": [ + { + "concept": "uk.benefits.universal_credit.amount", + "operator": ">", + "value": 0 + }, + { + "concept": "uk.household.children", + "operator": "==", + "value": 3 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/uc/claimants_with_3_children", + "reduce": "any", + "household_conditions": [ + { + "variable": "universal_credit", + "entity": "benunit", + "reduce": "any", + "operator": ">", + "value": 0 + }, + { + "variable": "is_child", + "entity": "person", + "reduce": "sum", + "operator": "==", + "value": 3 + } + ], + "value_variable": "household_count", + "notes": "Household indicator: any benunit on UC and the household child count matches (compute/benefits.py:33-51)." + }, + "axiom": { + "metric_name": "dwp/uc/claimants_with_3_children", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_households", + "groupby_dimension": "dwp.uc_number_of_children", + "dimension_values": { + "number_of_children": 3 + } + } + }, + { + "target_id": "dwp.uc.households_children_4", + "family": "dwp_universal_credit", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count", + "filters": [ + { + "concept": "uk.benefits.universal_credit.amount", + "operator": ">", + "value": 0 + }, + { + "concept": "uk.household.children", + "operator": "==", + "value": 4 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/uc/claimants_with_4_children", + "reduce": "any", + "household_conditions": [ + { + "variable": "universal_credit", + "entity": "benunit", + "reduce": "any", + "operator": ">", + "value": 0 + }, + { + "variable": "is_child", + "entity": "person", + "reduce": "sum", + "operator": "==", + "value": 4 + } + ], + "value_variable": "household_count", + "notes": "Household indicator: any benunit on UC and the household child count matches (compute/benefits.py:33-51)." + }, + "axiom": { + "metric_name": "dwp/uc/claimants_with_4_children", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_households", + "groupby_dimension": "dwp.uc_number_of_children", + "dimension_values": { + "number_of_children": 4 + } + } + }, + { + "target_id": "dwp.uc.households_children_5_or_more", + "family": "dwp_universal_credit", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count", + "filters": [ + { + "concept": "uk.benefits.universal_credit.amount", + "operator": ">", + "value": 0 + }, + { + "concept": "uk.household.children", + "operator": ">=", + "value": 5 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/uc/claimants_with_5+_children", + "reduce": "any", + "household_conditions": [ + { + "variable": "universal_credit", + "entity": "benunit", + "reduce": "any", + "operator": ">", + "value": 0 + }, + { + "variable": "is_child", + "entity": "person", + "reduce": "sum", + "operator": ">=", + "value": 5 + } + ], + "value_variable": "household_count", + "notes": "Household indicator: any benunit on UC and the household child count matches (compute/benefits.py:33-51)." + }, + "axiom": { + "metric_name": "dwp/uc/claimants_with_5+_children", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_households", + "groupby_dimension": "dwp.uc_number_of_children", + "dimension_values": { + "number_of_children": "5 or more" + } + } + }, + { + "target_id": "dwp.uc.households_single_no_children", + "family": "dwp_universal_credit", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count", + "filters": [ + { + "concept": "uk.benefits.universal_credit.amount", + "operator": ">", + "value": 0 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/uc/claimants_single_no_children", + "reduce": "any", + "household_conditions": [ + { + "variable": "universal_credit", + "entity": "benunit", + "reduce": "any", + "operator": ">", + "value": 0 + }, + { + "variable": "family_type", + "entity": "benunit", + "reduce": "any", + "operator": "==", + "value": "SINGLE" + }, + { + "variable": "is_child", + "entity": "person", + "reduce": "sum", + "operator": "==", + "value": 0 + } + ], + "value_variable": "household_count", + "notes": "Household indicator over benunit family type (compute/benefits.py:54-81). uk-data's +~0.021% undercount inflation is a populace-side value declaration." + }, + "axiom": { + "metric_name": "dwp/uc/claimants_single_no_children", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_households", + "groupby_dimension": "dwp.uc_family_type", + "dimension_values": { + "family_type": "Single, no children" + } + } + }, + { + "target_id": "dwp.uc.households_single_with_children", + "family": "dwp_universal_credit", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count", + "filters": [ + { + "concept": "uk.benefits.universal_credit.amount", + "operator": ">", + "value": 0 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/uc/claimants_single_with_children", + "reduce": "any", + "household_conditions": [ + { + "variable": "universal_credit", + "entity": "benunit", + "reduce": "any", + "operator": ">", + "value": 0 + }, + { + "variable": "family_type", + "entity": "benunit", + "reduce": "any", + "operator": "in", + "value": [ + "SINGLE", + "LONE_PARENT" + ] + }, + { + "variable": "is_child", + "entity": "person", + "reduce": "sum", + "operator": ">", + "value": 0 + } + ], + "value_variable": "household_count", + "notes": "DWP's single bucket does not distinguish PE-UK's SINGLE and LONE_PARENT (compute/benefits.py:54-81). uk-data's +~0.021% undercount inflation on these counts is a populace-side value declaration - the facts are the raw Stat-Xplore counts." + }, + "axiom": { + "metric_name": "dwp/uc/claimants_single_with_children", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_households", + "groupby_dimension": "dwp.uc_family_type", + "dimension_values": { + "family_type": "Single, with children" + } + } + }, + { + "target_id": "dwp.uc.households_couple_no_children", + "family": "dwp_universal_credit", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count", + "filters": [ + { + "concept": "uk.benefits.universal_credit.amount", + "operator": ">", + "value": 0 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/uc/claimants_couple_no_children", + "reduce": "any", + "household_conditions": [ + { + "variable": "universal_credit", + "entity": "benunit", + "reduce": "any", + "operator": ">", + "value": 0 + }, + { + "variable": "family_type", + "entity": "benunit", + "reduce": "any", + "operator": "==", + "value": "COUPLE_NO_CHILDREN" + } + ], + "value_variable": "household_count", + "notes": "Household indicator over benunit family type (compute/benefits.py:54-81). uk-data's +~0.021% undercount inflation is a populace-side value declaration." + }, + "axiom": { + "metric_name": "dwp/uc/claimants_couple_no_children", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_households", + "groupby_dimension": "dwp.uc_family_type", + "dimension_values": { + "family_type": "Couple, no children" + } + } + }, + { + "target_id": "dwp.uc.households_couple_with_children", + "family": "dwp_universal_credit", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count", + "filters": [ + { + "concept": "uk.benefits.universal_credit.amount", + "operator": ">", + "value": 0 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/uc/claimants_couple_with_children", + "reduce": "any", + "household_conditions": [ + { + "variable": "universal_credit", + "entity": "benunit", + "reduce": "any", + "operator": ">", + "value": 0 + }, + { + "variable": "family_type", + "entity": "benunit", + "reduce": "any", + "operator": "==", + "value": "COUPLE_WITH_CHILDREN" + } + ], + "value_variable": "household_count", + "notes": "Household indicator over benunit family type (compute/benefits.py:54-81). uk-data's +~0.021% undercount inflation is a populace-side value declaration." + }, + "axiom": { + "metric_name": "dwp/uc/claimants_couple_with_children", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_households", + "groupby_dimension": "dwp.uc_family_type", + "dimension_values": { + "family_type": "Couple, with children" + } + } + }, + { + "target_id": "dwp.uc.payment_distribution_single", + "family": "dwp_universal_credit", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "benunit", + "map_to": "household", + "concept": "uk.benefit_unit.count", + "groupby_dimension": "dwp.uc_monthly_award_band", + "filters": [ + { + "concept": "uk.benefits.universal_credit.amount", + "operator": ">", + "value": 0 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/uc_payment_dist/SINGLE", + "groupby_variable": "universal_credit", + "filters": [ + { + "variable": "family_type", + "operator": "==", + "value": "SINGLE" + } + ], + "value_variable": "benunit_count", + "from_entity": "benunit", + "map_to": "household", + "band_period_factor": 12, + "notes": "Benunit counts by annual UC award band: publisher bands are monthly award amounts, multiplied by 12 to band annual model UC (compute/benefits.py:84-98; half-open [lower, upper))." + }, + "axiom": { + "metric_name": "dwp/uc_payment_dist/SINGLE", + "status": "pending", + "value_rule": "uk.benefit_unit.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_households", + "groupby_dimension": "dwp.uc_monthly_award_band", + "dimension_values": { + "family_type": "Single, no children" + } + } + }, + { + "target_id": "dwp.uc.payment_distribution_lone_parent", + "family": "dwp_universal_credit", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "benunit", + "map_to": "household", + "concept": "uk.benefit_unit.count", + "groupby_dimension": "dwp.uc_monthly_award_band", + "filters": [ + { + "concept": "uk.benefits.universal_credit.amount", + "operator": ">", + "value": 0 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/uc_payment_dist/LONE_PARENT", + "groupby_variable": "universal_credit", + "filters": [ + { + "variable": "family_type", + "operator": "==", + "value": "LONE_PARENT" + } + ], + "value_variable": "benunit_count", + "from_entity": "benunit", + "map_to": "household", + "band_period_factor": 12, + "notes": "Benunit counts by annual UC award band: publisher bands are monthly award amounts, multiplied by 12 to band annual model UC (compute/benefits.py:84-98; half-open [lower, upper))." + }, + "axiom": { + "metric_name": "dwp/uc_payment_dist/LONE_PARENT", + "status": "pending", + "value_rule": "uk.benefit_unit.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_households", + "groupby_dimension": "dwp.uc_monthly_award_band", + "dimension_values": { + "family_type": "Single, with children" + } + } + }, + { + "target_id": "dwp.uc.payment_distribution_couple_no_children", + "family": "dwp_universal_credit", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "benunit", + "map_to": "household", + "concept": "uk.benefit_unit.count", + "groupby_dimension": "dwp.uc_monthly_award_band", + "filters": [ + { + "concept": "uk.benefits.universal_credit.amount", + "operator": ">", + "value": 0 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/uc_payment_dist/COUPLE_NO_CHILDREN", + "groupby_variable": "universal_credit", + "filters": [ + { + "variable": "family_type", + "operator": "==", + "value": "COUPLE_NO_CHILDREN" + } + ], + "value_variable": "benunit_count", + "from_entity": "benunit", + "map_to": "household", + "band_period_factor": 12, + "notes": "Benunit counts by annual UC award band: publisher bands are monthly award amounts, multiplied by 12 to band annual model UC (compute/benefits.py:84-98; half-open [lower, upper))." + }, + "axiom": { + "metric_name": "dwp/uc_payment_dist/COUPLE_NO_CHILDREN", + "status": "pending", + "value_rule": "uk.benefit_unit.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_households", + "groupby_dimension": "dwp.uc_monthly_award_band", + "dimension_values": { + "family_type": "Couple, no children" + } + } + }, + { + "target_id": "dwp.uc.payment_distribution_couple_with_children", + "family": "dwp_universal_credit", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "benunit", + "map_to": "household", + "concept": "uk.benefit_unit.count", + "groupby_dimension": "dwp.uc_monthly_award_band", + "filters": [ + { + "concept": "uk.benefits.universal_credit.amount", + "operator": ">", + "value": 0 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN", + "groupby_variable": "universal_credit", + "filters": [ + { + "variable": "family_type", + "operator": "==", + "value": "COUPLE_WITH_CHILDREN" + } + ], + "value_variable": "benunit_count", + "from_entity": "benunit", + "map_to": "household", + "band_period_factor": 12, + "notes": "Benunit counts by annual UC award band: publisher bands are monthly award amounts, multiplied by 12 to band annual model UC (compute/benefits.py:84-98; half-open [lower, upper))." + }, + "axiom": { + "metric_name": "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN", + "status": "pending", + "value_rule": "uk.benefit_unit.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_households", + "groupby_dimension": "dwp.uc_monthly_award_band", + "dimension_values": { + "family_type": "Couple, with children" + } + } + }, + { + "target_id": "dwp.uc.scotland_households_child_under_1", + "family": "dwp_universal_credit", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count", + "filters": [ + { + "concept": "uk.geography.region", + "equals": "scotland" + }, + { + "concept": "uk.benefits.universal_credit.amount", + "operator": ">", + "value": 0 + }, + { + "concept": "uk.demographics.youngest_child_age", + "operator": "<", + "value": 1 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/scotland_uc_households_child_under_1", + "reduce": "any", + "household_conditions": [ + { + "variable": "region", + "operator": "==", + "value": "SCOTLAND" + }, + { + "variable": "universal_credit", + "entity": "benunit", + "reduce": "any", + "operator": ">", + "value": 0 + }, + { + "variable": "age", + "entity": "person", + "reduce": "any_child_under", + "operator": "<", + "value": 1 + } + ], + "value_variable": "household_count", + "notes": "Scottish UC households with a child under 1 (compute/benefits.py:24-30)." + }, + "axiom": { + "metric_name": "dwp/scotland_uc_households_child_under_1", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_households", + "groupby_dimension": "dwp.uc_youngest_child_age", + "dimension_values": { + "age_of_youngest_child_bands_and_single_year": 0 + } + } + }, + { + "target_id": "dwp.uc.two_child_limit.households_affected", + "family": "dwp_two_child_limit", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count" + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/uc/two_child_limit/households_affected", + "kind": "baseline_flag_crosstab", + "affected_flag_variable": "uc_is_child_limit_affected", + "count_of": "affected_households", + "value_variable": "household_count", + "map_to": "household", + "notes": "Affected children are persons flagged by uc_is_child_limit_affected (household round-trip) who are children in UC-receiving households; an affected household contains at least one such child (compute/benefits.py:130-148)." + }, + "axiom": { + "metric_name": "dwp/uc/two_child_limit/households_affected", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_tcl_headline_households_affected", + "dimension_values": { + "two_child_limit_status": "affected_3plus_children" + } + } + }, + { + "target_id": "dwp.uc.two_child_limit.children_affected", + "family": "dwp_two_child_limit", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.person.count" + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/uc/two_child_limit/children_affected", + "kind": "baseline_flag_crosstab", + "affected_flag_variable": "uc_is_child_limit_affected", + "count_of": "affected_children", + "value_variable": "children_count", + "map_to": "household", + "notes": "Affected children are persons flagged by uc_is_child_limit_affected (household round-trip) who are children in UC-receiving households; an affected household contains at least one such child (compute/benefits.py:130-148)." + }, + "axiom": { + "metric_name": "dwp/uc/two_child_limit/children_affected", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_tcl_headline_children_affected_by_policy", + "dimension_values": { + "two_child_limit_status": "affected_3plus_children" + } + } + }, + { + "target_id": "dwp.uc.two_child_limit.children_in_affected_households", + "family": "dwp_two_child_limit", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.person.count" + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/uc/two_child_limit/children_in_affected_households", + "kind": "baseline_flag_crosstab", + "affected_flag_variable": "uc_is_child_limit_affected", + "count_of": "children_in_affected_households", + "value_variable": "children_count", + "map_to": "household", + "notes": "Affected children are persons flagged by uc_is_child_limit_affected (household round-trip) who are children in UC-receiving households; an affected household contains at least one such child (compute/benefits.py:130-148)." + }, + "axiom": { + "metric_name": "dwp/uc/two_child_limit/children_in_affected_households", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_tcl_headline_children_within_affected_households", + "dimension_values": { + "two_child_limit_status": "affected_3plus_children" + } + } + }, + { + "target_id": "dwp.uc.two_child_limit.households_3_children", + "family": "dwp_two_child_limit", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count" + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/uc/two_child_limit/3_children_households", + "household_conditions": [ + { + "variable": "is_child", + "entity": "person", + "reduce": "sum", + "operator": "==", + "value": 3 + } + ], + "kind": "baseline_flag_crosstab", + "affected_flag_variable": "uc_is_child_limit_affected", + "count_of": "affected_households", + "value_variable": "household_count", + "map_to": "household", + "notes": "Affected children are persons flagged by uc_is_child_limit_affected (household round-trip) who are children in UC-receiving households; an affected household contains at least one such child (compute/benefits.py:130-148)." + }, + "axiom": { + "metric_name": "dwp/uc/two_child_limit/3_children_households", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_tcl_households_by_children_3", + "dimension_values": { + "two_child_limit_status": "affected_3plus_children" + } + } + }, + { + "target_id": "dwp.uc.two_child_limit.children_in_3_children_households", + "family": "dwp_two_child_limit", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.person.count" + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/uc/two_child_limit/3_children_households_total_children", + "household_conditions": [ + { + "variable": "is_child", + "entity": "person", + "reduce": "sum", + "operator": "==", + "value": 3 + } + ], + "kind": "baseline_flag_crosstab", + "affected_flag_variable": "uc_is_child_limit_affected", + "count_of": "children_in_affected_households", + "value_variable": "children_count", + "map_to": "household", + "notes": "Total children (not only affected children) in affected households of this size (compute/benefits.py:158-161)." + }, + "axiom": { + "metric_name": "dwp/uc/two_child_limit/3_children_households_total_children", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_tcl_children_by_children_3", + "dimension_values": { + "two_child_limit_status": "affected_3plus_children" + } + } + }, + { + "target_id": "dwp.uc.two_child_limit.households_4_children", + "family": "dwp_two_child_limit", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count" + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/uc/two_child_limit/4_children_households", + "household_conditions": [ + { + "variable": "is_child", + "entity": "person", + "reduce": "sum", + "operator": "==", + "value": 4 + } + ], + "kind": "baseline_flag_crosstab", + "affected_flag_variable": "uc_is_child_limit_affected", + "count_of": "affected_households", + "value_variable": "household_count", + "map_to": "household", + "notes": "Affected children are persons flagged by uc_is_child_limit_affected (household round-trip) who are children in UC-receiving households; an affected household contains at least one such child (compute/benefits.py:130-148)." + }, + "axiom": { + "metric_name": "dwp/uc/two_child_limit/4_children_households", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_tcl_households_by_children_4", + "dimension_values": { + "two_child_limit_status": "affected_3plus_children" + } + } + }, + { + "target_id": "dwp.uc.two_child_limit.children_in_4_children_households", + "family": "dwp_two_child_limit", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.person.count" + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/uc/two_child_limit/4_children_households_total_children", + "household_conditions": [ + { + "variable": "is_child", + "entity": "person", + "reduce": "sum", + "operator": "==", + "value": 4 + } + ], + "kind": "baseline_flag_crosstab", + "affected_flag_variable": "uc_is_child_limit_affected", + "count_of": "children_in_affected_households", + "value_variable": "children_count", + "map_to": "household", + "notes": "Total children (not only affected children) in affected households of this size (compute/benefits.py:158-161)." + }, + "axiom": { + "metric_name": "dwp/uc/two_child_limit/4_children_households_total_children", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_tcl_children_by_children_4", + "dimension_values": { + "two_child_limit_status": "affected_3plus_children" + } + } + }, + { + "target_id": "dwp.uc.two_child_limit.households_5_children", + "family": "dwp_two_child_limit", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count" + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/uc/two_child_limit/5_children_households", + "household_conditions": [ + { + "variable": "is_child", + "entity": "person", + "reduce": "sum", + "operator": "==", + "value": 5 + } + ], + "kind": "baseline_flag_crosstab", + "affected_flag_variable": "uc_is_child_limit_affected", + "count_of": "affected_households", + "value_variable": "household_count", + "map_to": "household", + "notes": "Affected children are persons flagged by uc_is_child_limit_affected (household round-trip) who are children in UC-receiving households; an affected household contains at least one such child (compute/benefits.py:130-148)." + }, + "axiom": { + "metric_name": "dwp/uc/two_child_limit/5_children_households", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_tcl_households_by_children_5", + "dimension_values": { + "two_child_limit_status": "affected_3plus_children" + } + } + }, + { + "target_id": "dwp.uc.two_child_limit.children_in_5_children_households", + "family": "dwp_two_child_limit", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.person.count" + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/uc/two_child_limit/5_children_households_total_children", + "household_conditions": [ + { + "variable": "is_child", + "entity": "person", + "reduce": "sum", + "operator": "==", + "value": 5 + } + ], + "kind": "baseline_flag_crosstab", + "affected_flag_variable": "uc_is_child_limit_affected", + "count_of": "children_in_affected_households", + "value_variable": "children_count", + "map_to": "household", + "notes": "Total children (not only affected children) in affected households of this size (compute/benefits.py:158-161)." + }, + "axiom": { + "metric_name": "dwp/uc/two_child_limit/5_children_households_total_children", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_tcl_children_by_children_5", + "dimension_values": { + "two_child_limit_status": "affected_3plus_children" + } + } + }, + { + "target_id": "dwp.uc.two_child_limit.households_6_plus_children", + "family": "dwp_two_child_limit", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count" + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/uc/two_child_limit/6_children_households", + "household_conditions": [ + { + "variable": "is_child", + "entity": "person", + "reduce": "sum", + "operator": ">=", + "value": 6 + } + ], + "kind": "baseline_flag_crosstab", + "affected_flag_variable": "uc_is_child_limit_affected", + "count_of": "affected_households", + "value_variable": "household_count", + "map_to": "household", + "notes": "Affected children are persons flagged by uc_is_child_limit_affected (household round-trip) who are children in UC-receiving households; an affected household contains at least one such child (compute/benefits.py:130-148). Publisher's top band is 6-or-more children." + }, + "axiom": { + "metric_name": "dwp/uc/two_child_limit/6_children_households", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_tcl_households_by_children_6_plus", + "dimension_values": { + "two_child_limit_status": "affected_3plus_children" + } + } + }, + { + "target_id": "dwp.uc.two_child_limit.children_in_6_plus_children_households", + "family": "dwp_two_child_limit", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.person.count" + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/uc/two_child_limit/6_children_households_total_children", + "household_conditions": [ + { + "variable": "is_child", + "entity": "person", + "reduce": "sum", + "operator": ">=", + "value": 6 + } + ], + "kind": "baseline_flag_crosstab", + "affected_flag_variable": "uc_is_child_limit_affected", + "count_of": "children_in_affected_households", + "value_variable": "children_count", + "map_to": "household", + "notes": "Total children (not only affected children) in affected households of this size (compute/benefits.py:158-161)." + }, + "axiom": { + "metric_name": "dwp/uc/two_child_limit/6_children_households_total_children", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_tcl_children_by_children_6_plus", + "dimension_values": { + "two_child_limit_status": "affected_3plus_children" + } + } + }, + { + "target_id": "dwp.uc.two_child_limit.households_claimant_pip", + "family": "dwp_two_child_limit", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count" + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/uc/two_child_limit/adult_pip_households", + "household_conditions": [ + { + "variable": "pip", + "entity": "person", + "reduce": "sum", + "operator": ">", + "value": 0 + } + ], + "kind": "baseline_flag_crosstab", + "affected_flag_variable": "uc_is_child_limit_affected", + "count_of": "affected_households", + "value_variable": "household_count", + "map_to": "household", + "notes": "Affected children are persons flagged by uc_is_child_limit_affected (household round-trip) who are children in UC-receiving households; an affected household contains at least one such child (compute/benefits.py:130-148)." + }, + "axiom": { + "metric_name": "dwp/uc/two_child_limit/adult_pip_households", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_tcl_households_by_disability_claimant_pip", + "dimension_values": { + "two_child_limit_status": "affected_3plus_children" + } + } + }, + { + "target_id": "dwp.uc.two_child_limit.children_claimant_pip", + "family": "dwp_two_child_limit", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.person.count" + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/uc/two_child_limit/adult_pip_children", + "household_conditions": [ + { + "variable": "pip", + "entity": "person", + "reduce": "sum", + "operator": ">", + "value": 0 + } + ], + "kind": "baseline_flag_crosstab", + "affected_flag_variable": "uc_is_child_limit_affected", + "count_of": "affected_children", + "value_variable": "children_count", + "map_to": "household", + "notes": "Affected children are persons flagged by uc_is_child_limit_affected (household round-trip) who are children in UC-receiving households; an affected household contains at least one such child (compute/benefits.py:130-148)." + }, + "axiom": { + "metric_name": "dwp/uc/two_child_limit/adult_pip_children", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_tcl_children_by_disability_claimant_pip", + "dimension_values": { + "two_child_limit_status": "affected_3plus_children" + } + } + }, + { + "target_id": "dwp.uc.two_child_limit.households_disabled_child_element", + "family": "dwp_two_child_limit", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count" + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/uc/two_child_limit/disabled_child_element_households", + "household_conditions": [ + { + "variable": "uc_individual_disabled_child_element", + "entity": "person", + "reduce": "sum", + "operator": ">", + "value": 0 + } + ], + "kind": "baseline_flag_crosstab", + "affected_flag_variable": "uc_is_child_limit_affected", + "count_of": "affected_households", + "value_variable": "household_count", + "map_to": "household", + "notes": "Affected children are persons flagged by uc_is_child_limit_affected (household round-trip) who are children in UC-receiving households; an affected household contains at least one such child (compute/benefits.py:130-148)." + }, + "axiom": { + "metric_name": "dwp/uc/two_child_limit/disabled_child_element_households", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_tcl_households_by_disability_disabled_child_element", + "dimension_values": { + "two_child_limit_status": "affected_3plus_children" + } + } + }, + { + "target_id": "dwp.uc.two_child_limit.children_disabled_child_element", + "family": "dwp_two_child_limit", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.person.count" + }, + "bindings": { + "policyengine": { + "metric_name": "dwp/uc/two_child_limit/disabled_child_element_children", + "household_conditions": [ + { + "variable": "uc_individual_disabled_child_element", + "entity": "person", + "reduce": "sum", + "operator": ">", + "value": 0 + } + ], + "kind": "baseline_flag_crosstab", + "affected_flag_variable": "uc_is_child_limit_affected", + "count_of": "affected_children", + "value_variable": "children_count", + "map_to": "household", + "notes": "Affected children are persons flagged by uc_is_child_limit_affected (household round-trip) who are children in UC-receiving households; an affected household contains at least one such child (compute/benefits.py:130-148)." + }, + "axiom": { + "metric_name": "dwp/uc/two_child_limit/disabled_child_element_children", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "dwp", + "source_concept": "dwp.uc_tcl_children_by_disability_disabled_child_element", + "dimension_values": { + "two_child_limit_status": "affected_3plus_children" + } + } + }, + { + "target_id": "ons.population.uk_total", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count" + }, + "bindings": { + "policyengine": { + "metric_name": "ons/uk_population", + "filters": [ + { + "variable": "age", + "operator": ">=", + "value": 0 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household", + "notes": "uk-data values beyond the MYE vintages come from projections - a populace-side activation decision." + }, + "axiom": { + "metric_name": "ons/uk_population", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimensions": [] + } + }, + { + "target_id": "ons.population.age_0_9_by_region", + "family": "ons_population", + "geography_levels": [ + "country", + "region" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 0 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 9 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/regional_age/0_9", + "filters": [ + { + "variable": "age", + "operator": ">=", + "value": 0 + }, + { + "variable": "age", + "operator": "<=", + "value": 9 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household", + "notes": "One row per geography: English regions resolve at region level, Wales/Scotland/Northern Ireland at country level; the resolved geography binds the model region filter (compute/demographics.py:22-38)." + }, + "axiom": { + "metric_name": "ons/regional_age/0_9", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "age": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ] + } + } + }, + { + "target_id": "ons.population.age_10_19_by_region", + "family": "ons_population", + "geography_levels": [ + "country", + "region" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 10 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 19 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/regional_age/10_19", + "filters": [ + { + "variable": "age", + "operator": ">=", + "value": 10 + }, + { + "variable": "age", + "operator": "<=", + "value": 19 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household", + "notes": "One row per geography: English regions resolve at region level, Wales/Scotland/Northern Ireland at country level; the resolved geography binds the model region filter (compute/demographics.py:22-38)." + }, + "axiom": { + "metric_name": "ons/regional_age/10_19", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "age": [ + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19 + ] + } + } + }, + { + "target_id": "ons.population.age_20_29_by_region", + "family": "ons_population", + "geography_levels": [ + "country", + "region" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 20 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 29 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/regional_age/20_29", + "filters": [ + { + "variable": "age", + "operator": ">=", + "value": 20 + }, + { + "variable": "age", + "operator": "<=", + "value": 29 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household", + "notes": "One row per geography: English regions resolve at region level, Wales/Scotland/Northern Ireland at country level; the resolved geography binds the model region filter (compute/demographics.py:22-38)." + }, + "axiom": { + "metric_name": "ons/regional_age/20_29", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "age": [ + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29 + ] + } + } + }, + { + "target_id": "ons.population.age_30_39_by_region", + "family": "ons_population", + "geography_levels": [ + "country", + "region" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 30 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 39 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/regional_age/30_39", + "filters": [ + { + "variable": "age", + "operator": ">=", + "value": 30 + }, + { + "variable": "age", + "operator": "<=", + "value": 39 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household", + "notes": "One row per geography: English regions resolve at region level, Wales/Scotland/Northern Ireland at country level; the resolved geography binds the model region filter (compute/demographics.py:22-38)." + }, + "axiom": { + "metric_name": "ons/regional_age/30_39", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "age": [ + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39 + ] + } + } + }, + { + "target_id": "ons.population.age_40_49_by_region", + "family": "ons_population", + "geography_levels": [ + "country", + "region" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 40 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 49 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/regional_age/40_49", + "filters": [ + { + "variable": "age", + "operator": ">=", + "value": 40 + }, + { + "variable": "age", + "operator": "<=", + "value": 49 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household", + "notes": "One row per geography: English regions resolve at region level, Wales/Scotland/Northern Ireland at country level; the resolved geography binds the model region filter (compute/demographics.py:22-38)." + }, + "axiom": { + "metric_name": "ons/regional_age/40_49", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "age": [ + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49 + ] + } + } + }, + { + "target_id": "ons.population.age_50_59_by_region", + "family": "ons_population", + "geography_levels": [ + "country", + "region" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 50 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 59 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/regional_age/50_59", + "filters": [ + { + "variable": "age", + "operator": ">=", + "value": 50 + }, + { + "variable": "age", + "operator": "<=", + "value": 59 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household", + "notes": "One row per geography: English regions resolve at region level, Wales/Scotland/Northern Ireland at country level; the resolved geography binds the model region filter (compute/demographics.py:22-38)." + }, + "axiom": { + "metric_name": "ons/regional_age/50_59", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "age": [ + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59 + ] + } + } + }, + { + "target_id": "ons.population.age_60_69_by_region", + "family": "ons_population", + "geography_levels": [ + "country", + "region" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 60 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 69 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/regional_age/60_69", + "filters": [ + { + "variable": "age", + "operator": ">=", + "value": 60 + }, + { + "variable": "age", + "operator": "<=", + "value": 69 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household", + "notes": "One row per geography: English regions resolve at region level, Wales/Scotland/Northern Ireland at country level; the resolved geography binds the model region filter (compute/demographics.py:22-38)." + }, + "axiom": { + "metric_name": "ons/regional_age/60_69", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "age": [ + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69 + ] + } + } + }, + { + "target_id": "ons.population.age_70_79_by_region", + "family": "ons_population", + "geography_levels": [ + "country", + "region" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 70 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 79 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/regional_age/70_79", + "filters": [ + { + "variable": "age", + "operator": ">=", + "value": 70 + }, + { + "variable": "age", + "operator": "<=", + "value": 79 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household", + "notes": "One row per geography: English regions resolve at region level, Wales/Scotland/Northern Ireland at country level; the resolved geography binds the model region filter (compute/demographics.py:22-38)." + }, + "axiom": { + "metric_name": "ons/regional_age/70_79", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "age": [ + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79 + ] + } + } + }, + { + "target_id": "ons.population.age_80_89_by_region", + "family": "ons_population", + "geography_levels": [ + "country", + "region" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 80 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 89 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/regional_age/80_89", + "filters": [ + { + "variable": "age", + "operator": ">=", + "value": 80 + }, + { + "variable": "age", + "operator": "<=", + "value": 89 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household", + "notes": "One row per geography: English regions resolve at region level, Wales/Scotland/Northern Ireland at country level; the resolved geography binds the model region filter (compute/demographics.py:22-38)." + }, + "axiom": { + "metric_name": "ons/regional_age/80_89", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "age": [ + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89 + ] + } + } + }, + { + "target_id": "ons.population.female_0_4", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "female" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 0 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 4 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/female_0_4", + "filters": [ + { + "variable": "gender", + "equals": "FEMALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 0 + }, + { + "variable": "age", + "operator": "<=", + "value": 4 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/female_0_4", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "female", + "age": [ + 0, + 1, + 2, + 3, + 4 + ] + } + } + }, + { + "target_id": "ons.population.female_10_14", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "female" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 10 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 14 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/female_10_14", + "filters": [ + { + "variable": "gender", + "equals": "FEMALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 10 + }, + { + "variable": "age", + "operator": "<=", + "value": 14 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/female_10_14", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "female", + "age": [ + 10, + 11, + 12, + 13, + 14 + ] + } + } + }, + { + "target_id": "ons.population.female_15_19", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "female" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 15 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 19 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/female_15_19", + "filters": [ + { + "variable": "gender", + "equals": "FEMALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 15 + }, + { + "variable": "age", + "operator": "<=", + "value": 19 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/female_15_19", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "female", + "age": [ + 15, + 16, + 17, + 18, + 19 + ] + } + } + }, + { + "target_id": "ons.population.female_20_24", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "female" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 20 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 24 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/female_20_24", + "filters": [ + { + "variable": "gender", + "equals": "FEMALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 20 + }, + { + "variable": "age", + "operator": "<=", + "value": 24 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/female_20_24", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "female", + "age": [ + 20, + 21, + 22, + 23, + 24 + ] + } + } + }, + { + "target_id": "ons.population.female_25_29", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "female" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 25 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 29 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/female_25_29", + "filters": [ + { + "variable": "gender", + "equals": "FEMALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 25 + }, + { + "variable": "age", + "operator": "<=", + "value": 29 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/female_25_29", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "female", + "age": [ + 25, + 26, + 27, + 28, + 29 + ] + } + } + }, + { + "target_id": "ons.population.female_30_34", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "female" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 30 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 34 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/female_30_34", + "filters": [ + { + "variable": "gender", + "equals": "FEMALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 30 + }, + { + "variable": "age", + "operator": "<=", + "value": 34 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/female_30_34", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "female", + "age": [ + 30, + 31, + 32, + 33, + 34 + ] + } + } + }, + { + "target_id": "ons.population.female_35_39", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "female" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 35 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 39 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/female_35_39", + "filters": [ + { + "variable": "gender", + "equals": "FEMALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 35 + }, + { + "variable": "age", + "operator": "<=", + "value": 39 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/female_35_39", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "female", + "age": [ + 35, + 36, + 37, + 38, + 39 + ] + } + } + }, + { + "target_id": "ons.population.female_40_44", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "female" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 40 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 44 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/female_40_44", + "filters": [ + { + "variable": "gender", + "equals": "FEMALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 40 + }, + { + "variable": "age", + "operator": "<=", + "value": 44 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/female_40_44", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "female", + "age": [ + 40, + 41, + 42, + 43, + 44 + ] + } + } + }, + { + "target_id": "ons.population.female_45_49", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "female" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 45 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 49 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/female_45_49", + "filters": [ + { + "variable": "gender", + "equals": "FEMALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 45 + }, + { + "variable": "age", + "operator": "<=", + "value": 49 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/female_45_49", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "female", + "age": [ + 45, + 46, + 47, + 48, + 49 + ] + } + } + }, + { + "target_id": "ons.population.female_50_54", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "female" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 50 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 54 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/female_50_54", + "filters": [ + { + "variable": "gender", + "equals": "FEMALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 50 + }, + { + "variable": "age", + "operator": "<=", + "value": 54 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/female_50_54", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "female", + "age": [ + 50, + 51, + 52, + 53, + 54 + ] + } + } + }, + { + "target_id": "ons.population.female_55_59", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "female" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 55 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 59 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/female_55_59", + "filters": [ + { + "variable": "gender", + "equals": "FEMALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 55 + }, + { + "variable": "age", + "operator": "<=", + "value": 59 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/female_55_59", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "female", + "age": [ + 55, + 56, + 57, + 58, + 59 + ] + } + } + }, + { + "target_id": "ons.population.female_5_9", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "female" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 5 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 9 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/female_5_9", + "filters": [ + { + "variable": "gender", + "equals": "FEMALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 5 + }, + { + "variable": "age", + "operator": "<=", + "value": 9 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/female_5_9", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "female", + "age": [ + 5, + 6, + 7, + 8, + 9 + ] + } + } + }, + { + "target_id": "ons.population.female_60_64", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "female" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 60 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 64 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/female_60_64", + "filters": [ + { + "variable": "gender", + "equals": "FEMALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 60 + }, + { + "variable": "age", + "operator": "<=", + "value": 64 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/female_60_64", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "female", + "age": [ + 60, + 61, + 62, + 63, + 64 + ] + } + } + }, + { + "target_id": "ons.population.female_65_69", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "female" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 65 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 69 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/female_65_69", + "filters": [ + { + "variable": "gender", + "equals": "FEMALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 65 + }, + { + "variable": "age", + "operator": "<=", + "value": 69 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/female_65_69", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "female", + "age": [ + 65, + 66, + 67, + 68, + 69 + ] + } + } + }, + { + "target_id": "ons.population.female_70_74", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "female" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 70 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 74 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/female_70_74", + "filters": [ + { + "variable": "gender", + "equals": "FEMALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 70 + }, + { + "variable": "age", + "operator": "<=", + "value": 74 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/female_70_74", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "female", + "age": [ + 70, + 71, + 72, + 73, + 74 + ] + } + } + }, + { + "target_id": "ons.population.female_75_79", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "female" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 75 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 79 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/female_75_79", + "filters": [ + { + "variable": "gender", + "equals": "FEMALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 75 + }, + { + "variable": "age", + "operator": "<=", + "value": 79 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/female_75_79", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "female", + "age": [ + 75, + 76, + 77, + 78, + 79 + ] + } + } + }, + { + "target_id": "ons.population.female_80_84", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "female" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 80 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 84 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/female_80_84", + "filters": [ + { + "variable": "gender", + "equals": "FEMALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 80 + }, + { + "variable": "age", + "operator": "<=", + "value": 84 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/female_80_84", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "female", + "age": [ + 80, + 81, + 82, + 83, + 84 + ] + } + } + }, + { + "target_id": "ons.population.female_85_90", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "female" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 85 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 90 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/female_85_90", + "filters": [ + { + "variable": "gender", + "equals": "FEMALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 85 + }, + { + "variable": "age", + "operator": "<=", + "value": 90 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/female_85_90", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "female", + "age": [ + 85, + 86, + 87, + 88, + 89, + "90_plus" + ] + } + } + }, + { + "target_id": "ons.population.male_0_4", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "male" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 0 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 4 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/male_0_4", + "filters": [ + { + "variable": "gender", + "equals": "MALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 0 + }, + { + "variable": "age", + "operator": "<=", + "value": 4 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/male_0_4", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "male", + "age": [ + 0, + 1, + 2, + 3, + 4 + ] + } + } + }, + { + "target_id": "ons.population.male_10_14", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "male" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 10 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 14 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/male_10_14", + "filters": [ + { + "variable": "gender", + "equals": "MALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 10 + }, + { + "variable": "age", + "operator": "<=", + "value": 14 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/male_10_14", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "male", + "age": [ + 10, + 11, + 12, + 13, + 14 + ] + } + } + }, + { + "target_id": "ons.population.male_15_19", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "male" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 15 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 19 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/male_15_19", + "filters": [ + { + "variable": "gender", + "equals": "MALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 15 + }, + { + "variable": "age", + "operator": "<=", + "value": 19 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/male_15_19", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "male", + "age": [ + 15, + 16, + 17, + 18, + 19 + ] + } + } + }, + { + "target_id": "ons.population.male_20_24", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "male" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 20 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 24 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/male_20_24", + "filters": [ + { + "variable": "gender", + "equals": "MALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 20 + }, + { + "variable": "age", + "operator": "<=", + "value": 24 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/male_20_24", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "male", + "age": [ + 20, + 21, + 22, + 23, + 24 + ] + } + } + }, + { + "target_id": "ons.population.male_25_29", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "male" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 25 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 29 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/male_25_29", + "filters": [ + { + "variable": "gender", + "equals": "MALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 25 + }, + { + "variable": "age", + "operator": "<=", + "value": 29 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/male_25_29", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "male", + "age": [ + 25, + 26, + 27, + 28, + 29 + ] + } + } + }, + { + "target_id": "ons.population.male_30_34", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "male" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 30 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 34 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/male_30_34", + "filters": [ + { + "variable": "gender", + "equals": "MALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 30 + }, + { + "variable": "age", + "operator": "<=", + "value": 34 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/male_30_34", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "male", + "age": [ + 30, + 31, + 32, + 33, + 34 + ] + } + } + }, + { + "target_id": "ons.population.male_35_39", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "male" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 35 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 39 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/male_35_39", + "filters": [ + { + "variable": "gender", + "equals": "MALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 35 + }, + { + "variable": "age", + "operator": "<=", + "value": 39 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/male_35_39", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "male", + "age": [ + 35, + 36, + 37, + 38, + 39 + ] + } + } + }, + { + "target_id": "ons.population.male_40_44", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "male" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 40 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 44 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/male_40_44", + "filters": [ + { + "variable": "gender", + "equals": "MALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 40 + }, + { + "variable": "age", + "operator": "<=", + "value": 44 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/male_40_44", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "male", + "age": [ + 40, + 41, + 42, + 43, + 44 + ] + } + } + }, + { + "target_id": "ons.population.male_45_49", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "male" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 45 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 49 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/male_45_49", + "filters": [ + { + "variable": "gender", + "equals": "MALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 45 + }, + { + "variable": "age", + "operator": "<=", + "value": 49 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/male_45_49", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "male", + "age": [ + 45, + 46, + 47, + 48, + 49 + ] + } + } + }, + { + "target_id": "ons.population.male_50_54", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "male" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 50 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 54 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/male_50_54", + "filters": [ + { + "variable": "gender", + "equals": "MALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 50 + }, + { + "variable": "age", + "operator": "<=", + "value": 54 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/male_50_54", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "male", + "age": [ + 50, + 51, + 52, + 53, + 54 + ] + } + } + }, + { + "target_id": "ons.population.male_55_59", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "male" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 55 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 59 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/male_55_59", + "filters": [ + { + "variable": "gender", + "equals": "MALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 55 + }, + { + "variable": "age", + "operator": "<=", + "value": 59 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/male_55_59", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "male", + "age": [ + 55, + 56, + 57, + 58, + 59 + ] + } + } + }, + { + "target_id": "ons.population.male_5_9", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "male" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 5 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 9 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/male_5_9", + "filters": [ + { + "variable": "gender", + "equals": "MALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 5 + }, + { + "variable": "age", + "operator": "<=", + "value": 9 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/male_5_9", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "male", + "age": [ + 5, + 6, + 7, + 8, + 9 + ] + } + } + }, + { + "target_id": "ons.population.male_60_64", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "male" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 60 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 64 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/male_60_64", + "filters": [ + { + "variable": "gender", + "equals": "MALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 60 + }, + { + "variable": "age", + "operator": "<=", + "value": 64 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/male_60_64", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "male", + "age": [ + 60, + 61, + 62, + 63, + 64 + ] + } + } + }, + { + "target_id": "ons.population.male_65_69", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "male" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 65 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 69 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/male_65_69", + "filters": [ + { + "variable": "gender", + "equals": "MALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 65 + }, + { + "variable": "age", + "operator": "<=", + "value": 69 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/male_65_69", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "male", + "age": [ + 65, + 66, + 67, + 68, + 69 + ] + } + } + }, + { + "target_id": "ons.population.male_70_74", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "male" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 70 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 74 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/male_70_74", + "filters": [ + { + "variable": "gender", + "equals": "MALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 70 + }, + { + "variable": "age", + "operator": "<=", + "value": 74 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/male_70_74", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "male", + "age": [ + 70, + 71, + 72, + 73, + 74 + ] + } + } + }, + { + "target_id": "ons.population.male_75_79", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "male" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 75 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 79 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/male_75_79", + "filters": [ + { + "variable": "gender", + "equals": "MALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 75 + }, + { + "variable": "age", + "operator": "<=", + "value": 79 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/male_75_79", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "male", + "age": [ + 75, + 76, + 77, + 78, + 79 + ] + } + } + }, + { + "target_id": "ons.population.male_80_84", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "male" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 80 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 84 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/male_80_84", + "filters": [ + { + "variable": "gender", + "equals": "MALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 80 + }, + { + "variable": "age", + "operator": "<=", + "value": 84 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/male_80_84", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "male", + "age": [ + 80, + 81, + 82, + 83, + 84 + ] + } + } + }, + { + "target_id": "ons.population.male_85_90", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.demographics.gender", + "equals": "male" + }, + { + "concept": "uk.demographics.age", + "operator": ">=", + "value": 85 + }, + { + "concept": "uk.demographics.age", + "operator": "<=", + "value": 90 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/male_85_90", + "filters": [ + { + "variable": "gender", + "equals": "MALE" + }, + { + "variable": "age", + "operator": ">=", + "value": 85 + }, + { + "variable": "age", + "operator": "<=", + "value": 90 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/male_85_90", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "sex": "male", + "age": [ + 85, + 86, + 87, + 88, + 89, + "90_plus" + ] + } + } + }, + { + "target_id": "ons.population.scotland_children_under_16", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.geography.region", + "equals": "scotland" + }, + { + "concept": "uk.demographics.age", + "operator": "<", + "value": 16 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/scotland_children_under_16", + "filters": [ + { + "variable": "region", + "equals": "SCOTLAND" + }, + { + "variable": "age", + "operator": "<", + "value": 16 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/scotland_children_under_16", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "age": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15 + ] + } + } + }, + { + "target_id": "ons.population.scotland_babies_under_1", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.geography.region", + "equals": "scotland" + }, + { + "concept": "uk.demographics.age", + "operator": "<", + "value": 1 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/scotland_babies_under_1", + "filters": [ + { + "variable": "region", + "equals": "SCOTLAND" + }, + { + "variable": "age", + "operator": "<", + "value": 1 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/scotland_babies_under_1", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age", + "dimension_values": { + "age": [ + 0 + ] + } + } + }, + { + "target_id": "ons.population.scotland_households_3plus_children", + "family": "ons_population", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count", + "filters": [ + { + "concept": "uk.geography.region", + "equals": "scotland" + }, + { + "concept": "uk.household.children", + "operator": ">=", + "value": 3 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/scotland_households_3plus_children", + "reduce": "any", + "household_conditions": [ + { + "variable": "region", + "operator": "==", + "value": "SCOTLAND" + }, + { + "variable": "is_child", + "entity": "person", + "reduce": "sum", + "operator": ">=", + "value": 3 + } + ], + "value_variable": "household_count", + "notes": "Household indicator (compute/demographics.py:60-77)." + }, + "axiom": { + "metric_name": "ons/scotland_households_3plus_children", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.mid_year_population_estimate", + "groupby_dimension": "age" + } + }, + { + "target_id": "ons.household_composition.lone_households_under_65", + "family": "ons_household_composition", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count" + }, + "bindings": { + "policyengine": { + "metric_name": "ons/lone_households_under_65", + "reduce": "any", + "household_conditions": [ + { + "variable": "family_type", + "entity": "benunit", + "reduce": "any", + "operator": "==", + "value": "SINGLE" + }, + { + "variable": "is_child", + "entity": "person", + "reduce": "sum", + "operator": "==", + "value": 0 + }, + { + "variable": "age", + "entity": "person", + "reduce": "sum", + "operator": "<", + "value": 65 + } + ], + "value_variable": "household_count", + "notes": "uk-data reads ctx.pe('age') - person ages summed to household - as the head's age; exact only for single-person households (compute/households.py:12)." + }, + "axiom": { + "metric_name": "ons/lone_households_under_65", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.families_households_table7", + "groupby_dimension": "ons.household_type", + "dimension_values": { + "household_type": "lone_households_under_65" + } + } + }, + { + "target_id": "ons.household_composition.lone_households_over_65", + "family": "ons_household_composition", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count" + }, + "bindings": { + "policyengine": { + "metric_name": "ons/lone_households_over_65", + "reduce": "any", + "household_conditions": [ + { + "variable": "family_type", + "entity": "benunit", + "reduce": "any", + "operator": "==", + "value": "SINGLE" + }, + { + "variable": "is_child", + "entity": "person", + "reduce": "sum", + "operator": "==", + "value": 0 + }, + { + "variable": "age", + "entity": "person", + "reduce": "sum", + "operator": ">=", + "value": 65 + } + ], + "value_variable": "household_count", + "notes": "uk-data reads ctx.pe('age') - person ages summed to household - as the head's age; exact only for single-person households (compute/households.py:12)." + }, + "axiom": { + "metric_name": "ons/lone_households_over_65", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.families_households_table7", + "groupby_dimension": "ons.household_type", + "dimension_values": { + "household_type": "lone_households_over_65" + } + } + }, + { + "target_id": "ons.household_composition.unrelated_adult_households", + "family": "ons_household_composition", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count" + }, + "bindings": { + "policyengine": { + "metric_name": "ons/unrelated_adult_households", + "reduce": "any", + "household_conditions": [ + { + "variable": "family_type", + "entity": "benunit", + "reduce": "any", + "operator": "==", + "value": "SINGLE" + }, + { + "variable": "is_child", + "entity": "person", + "reduce": "sum", + "operator": "==", + "value": 0 + }, + { + "variable": "age", + "entity": "person", + "reduce": "count", + "operator": ">", + "value": 1 + } + ], + "value_variable": "household_count" + }, + "axiom": { + "metric_name": "ons/unrelated_adult_households", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.families_households_table7", + "groupby_dimension": "ons.household_type", + "dimension_values": { + "household_type": "unrelated_adult_households" + } + } + }, + { + "target_id": "ons.household_composition.couple_no_children_households", + "family": "ons_household_composition", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count" + }, + "bindings": { + "policyengine": { + "metric_name": "ons/couple_no_children_households", + "reduce": "any", + "household_conditions": [ + { + "variable": "family_type", + "entity": "benunit", + "reduce": "any", + "operator": "==", + "value": "COUPLE_NO_CHILDREN" + } + ], + "value_variable": "household_count" + }, + "axiom": { + "metric_name": "ons/couple_no_children_households", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.families_households_table7", + "groupby_dimension": "ons.household_type", + "dimension_values": { + "household_type": "couple_no_children_households" + } + } + }, + { + "target_id": "ons.household_composition.couple_under_3_children_households", + "family": "ons_household_composition", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count" + }, + "bindings": { + "policyengine": { + "metric_name": "ons/couple_under_3_children_households", + "reduce": "any", + "household_conditions": [ + { + "variable": "family_type", + "entity": "benunit", + "reduce": "any", + "operator": "==", + "value": "COUPLE_WITH_CHILDREN" + }, + { + "variable": "is_child", + "entity": "person", + "reduce": "sum", + "operator": ">=", + "value": 1 + }, + { + "variable": "is_child", + "entity": "person", + "reduce": "sum", + "operator": "<=", + "value": 2 + } + ], + "value_variable": "household_count" + }, + "axiom": { + "metric_name": "ons/couple_under_3_children_households", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.families_households_table7", + "groupby_dimension": "ons.household_type", + "dimension_values": { + "household_type": "couple_under_3_children_households" + } + } + }, + { + "target_id": "ons.household_composition.couple_3_plus_children_households", + "family": "ons_household_composition", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count" + }, + "bindings": { + "policyengine": { + "metric_name": "ons/couple_3_plus_children_households", + "reduce": "any", + "household_conditions": [ + { + "variable": "family_type", + "entity": "benunit", + "reduce": "any", + "operator": "==", + "value": "COUPLE_WITH_CHILDREN" + }, + { + "variable": "is_child", + "entity": "person", + "reduce": "sum", + "operator": ">=", + "value": 3 + } + ], + "value_variable": "household_count" + }, + "axiom": { + "metric_name": "ons/couple_3_plus_children_households", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.families_households_table7", + "groupby_dimension": "ons.household_type", + "dimension_values": { + "household_type": "couple_3_plus_children_households" + } + } + }, + { + "target_id": "ons.household_composition.couple_non_dependent_children_only_households", + "family": "ons_household_composition", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count" + }, + "bindings": { + "policyengine": { + "metric_name": "ons/couple_non_dependent_children_only_households", + "reduce": "any", + "household_conditions": [ + { + "variable": "family_type", + "entity": "benunit", + "reduce": "any", + "operator": "==", + "value": "COUPLE_NO_CHILDREN" + }, + { + "variable": "age", + "entity": "person", + "reduce": "count", + "operator": ">", + "value": 2 + } + ], + "value_variable": "household_count", + "notes": "Proxied: couple benunit with additional non-dependent people (compute/households.py:40-42)." + }, + "axiom": { + "metric_name": "ons/couple_non_dependent_children_only_households", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.families_households_table7", + "groupby_dimension": "ons.household_type", + "dimension_values": { + "household_type": "couple_non_dependent_children_only_households" + } + } + }, + { + "target_id": "ons.household_composition.lone_parent_dependent_children_households", + "family": "ons_household_composition", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count" + }, + "bindings": { + "policyengine": { + "metric_name": "ons/lone_parent_dependent_children_households", + "reduce": "any", + "household_conditions": [ + { + "variable": "family_type", + "entity": "benunit", + "reduce": "any", + "operator": "==", + "value": "LONE_PARENT" + }, + { + "variable": "is_child", + "entity": "person", + "reduce": "sum", + "operator": ">", + "value": 0 + } + ], + "value_variable": "household_count" + }, + "axiom": { + "metric_name": "ons/lone_parent_dependent_children_households", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.families_households_table7", + "groupby_dimension": "ons.household_type", + "dimension_values": { + "household_type": "lone_parent_dependent_children_households" + } + } + }, + { + "target_id": "ons.household_composition.lone_parent_non_dependent_children_households", + "family": "ons_household_composition", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count" + }, + "bindings": { + "policyengine": { + "metric_name": "ons/lone_parent_non_dependent_children_households", + "reduce": "any", + "household_conditions": [ + { + "variable": "family_type", + "entity": "benunit", + "reduce": "any", + "operator": "==", + "value": "SINGLE" + }, + { + "variable": "is_child", + "entity": "person", + "reduce": "sum", + "operator": "==", + "value": 0 + }, + { + "variable": "age", + "entity": "person", + "reduce": "count", + "operator": ">", + "value": 1 + }, + { + "variable": "age", + "entity": "person", + "reduce": "sum", + "operator": ">=", + "value": 40 + } + ], + "value_variable": "household_count", + "notes": "Proxied: single benunit, no dependent children, more than one person, head aged 40+ (compute/households.py:45-52). uk-data reads ctx.pe('age') - person ages summed to household - as the head's age; exact only for single-person households (compute/households.py:12)." + }, + "axiom": { + "metric_name": "ons/lone_parent_non_dependent_children_households", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.families_households_table7", + "groupby_dimension": "ons.household_type", + "dimension_values": { + "household_type": "lone_parent_non_dependent_children_households" + } + } + }, + { + "target_id": "ons.household_composition.multi_family_households", + "family": "ons_household_composition", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count" + }, + "bindings": { + "policyengine": { + "metric_name": "ons/multi_family_households", + "reduce": "any", + "household_conditions": [ + { + "variable": "household_num_benunits", + "operator": ">", + "value": 1 + } + ], + "value_variable": "household_count" + }, + "axiom": { + "metric_name": "ons/multi_family_households", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.families_households_table7", + "groupby_dimension": "ons.household_type", + "dimension_values": { + "household_type": "multi_family_households" + } + } + }, + { + "target_id": "voa.council_tax_stock.band_a", + "family": "council_tax_stock", + "geography_levels": [ + "region", + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count", + "filters": [ + { + "concept": "uk.housing.council_tax_band", + "equals": "A" + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "voa/council_tax/band_a", + "reduce": "any", + "household_conditions": [ + { + "variable": "council_tax_band", + "operator": "==", + "value": "A" + } + ], + "value_variable": "household_count", + "notes": "Dwelling stock proxied by households; one row per VOA geography (English regions at region level, Wales at country level) - the resolved geography binds the region filter (compute/council_tax.py:6-18). uk-data does not target VOA band I." + }, + "axiom": { + "metric_name": "voa/council_tax/band_a", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "voa", + "source_measure_id": "band_a" + } + }, + { + "target_id": "scotgov.council_tax_stock.band_a", + "family": "council_tax_stock", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count", + "filters": [ + { + "concept": "uk.housing.council_tax_band", + "equals": "A" + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "voa/council_tax/SCOTLAND/band_a", + "reduce": "any", + "household_conditions": [ + { + "variable": "council_tax_band", + "operator": "==", + "value": "A" + }, + { + "variable": "region", + "operator": "==", + "value": "SCOTLAND" + } + ], + "value_variable": "household_count", + "notes": "Scottish chargeable dwellings (CTAXBASE September 2025); uk-data files these under voa/council_tax/SCOTLAND/*." + }, + "axiom": { + "metric_name": "voa/council_tax/SCOTLAND/band_a", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "scotgov", + "source_measure_id": "band_a" + } + }, + { + "target_id": "voa.council_tax_stock.band_b", + "family": "council_tax_stock", + "geography_levels": [ + "region", + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count", + "filters": [ + { + "concept": "uk.housing.council_tax_band", + "equals": "B" + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "voa/council_tax/band_b", + "reduce": "any", + "household_conditions": [ + { + "variable": "council_tax_band", + "operator": "==", + "value": "B" + } + ], + "value_variable": "household_count", + "notes": "Dwelling stock proxied by households; one row per VOA geography (English regions at region level, Wales at country level) - the resolved geography binds the region filter (compute/council_tax.py:6-18). uk-data does not target VOA band I." + }, + "axiom": { + "metric_name": "voa/council_tax/band_b", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "voa", + "source_measure_id": "band_b" + } + }, + { + "target_id": "scotgov.council_tax_stock.band_b", + "family": "council_tax_stock", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count", + "filters": [ + { + "concept": "uk.housing.council_tax_band", + "equals": "B" + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "voa/council_tax/SCOTLAND/band_b", + "reduce": "any", + "household_conditions": [ + { + "variable": "council_tax_band", + "operator": "==", + "value": "B" + }, + { + "variable": "region", + "operator": "==", + "value": "SCOTLAND" + } + ], + "value_variable": "household_count", + "notes": "Scottish chargeable dwellings (CTAXBASE September 2025); uk-data files these under voa/council_tax/SCOTLAND/*." + }, + "axiom": { + "metric_name": "voa/council_tax/SCOTLAND/band_b", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "scotgov", + "source_measure_id": "band_b" + } + }, + { + "target_id": "voa.council_tax_stock.band_c", + "family": "council_tax_stock", + "geography_levels": [ + "region", + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count", + "filters": [ + { + "concept": "uk.housing.council_tax_band", + "equals": "C" + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "voa/council_tax/band_c", + "reduce": "any", + "household_conditions": [ + { + "variable": "council_tax_band", + "operator": "==", + "value": "C" + } + ], + "value_variable": "household_count", + "notes": "Dwelling stock proxied by households; one row per VOA geography (English regions at region level, Wales at country level) - the resolved geography binds the region filter (compute/council_tax.py:6-18). uk-data does not target VOA band I." + }, + "axiom": { + "metric_name": "voa/council_tax/band_c", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "voa", + "source_measure_id": "band_c" + } + }, + { + "target_id": "scotgov.council_tax_stock.band_c", + "family": "council_tax_stock", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count", + "filters": [ + { + "concept": "uk.housing.council_tax_band", + "equals": "C" + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "voa/council_tax/SCOTLAND/band_c", + "reduce": "any", + "household_conditions": [ + { + "variable": "council_tax_band", + "operator": "==", + "value": "C" + }, + { + "variable": "region", + "operator": "==", + "value": "SCOTLAND" + } + ], + "value_variable": "household_count", + "notes": "Scottish chargeable dwellings (CTAXBASE September 2025); uk-data files these under voa/council_tax/SCOTLAND/*." + }, + "axiom": { + "metric_name": "voa/council_tax/SCOTLAND/band_c", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "scotgov", + "source_measure_id": "band_c" + } + }, + { + "target_id": "voa.council_tax_stock.band_d", + "family": "council_tax_stock", + "geography_levels": [ + "region", + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count", + "filters": [ + { + "concept": "uk.housing.council_tax_band", + "equals": "D" + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "voa/council_tax/band_d", + "reduce": "any", + "household_conditions": [ + { + "variable": "council_tax_band", + "operator": "==", + "value": "D" + } + ], + "value_variable": "household_count", + "notes": "Dwelling stock proxied by households; one row per VOA geography (English regions at region level, Wales at country level) - the resolved geography binds the region filter (compute/council_tax.py:6-18). uk-data does not target VOA band I." + }, + "axiom": { + "metric_name": "voa/council_tax/band_d", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "voa", + "source_measure_id": "band_d" + } + }, + { + "target_id": "scotgov.council_tax_stock.band_d", + "family": "council_tax_stock", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count", + "filters": [ + { + "concept": "uk.housing.council_tax_band", + "equals": "D" + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "voa/council_tax/SCOTLAND/band_d", + "reduce": "any", + "household_conditions": [ + { + "variable": "council_tax_band", + "operator": "==", + "value": "D" + }, + { + "variable": "region", + "operator": "==", + "value": "SCOTLAND" + } + ], + "value_variable": "household_count", + "notes": "Scottish chargeable dwellings (CTAXBASE September 2025); uk-data files these under voa/council_tax/SCOTLAND/*." + }, + "axiom": { + "metric_name": "voa/council_tax/SCOTLAND/band_d", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "scotgov", + "source_measure_id": "band_d" + } + }, + { + "target_id": "voa.council_tax_stock.band_e", + "family": "council_tax_stock", + "geography_levels": [ + "region", + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count", + "filters": [ + { + "concept": "uk.housing.council_tax_band", + "equals": "E" + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "voa/council_tax/band_e", + "reduce": "any", + "household_conditions": [ + { + "variable": "council_tax_band", + "operator": "==", + "value": "E" + } + ], + "value_variable": "household_count", + "notes": "Dwelling stock proxied by households; one row per VOA geography (English regions at region level, Wales at country level) - the resolved geography binds the region filter (compute/council_tax.py:6-18). uk-data does not target VOA band I." + }, + "axiom": { + "metric_name": "voa/council_tax/band_e", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "voa", + "source_measure_id": "band_e" + } + }, + { + "target_id": "scotgov.council_tax_stock.band_e", + "family": "council_tax_stock", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count", + "filters": [ + { + "concept": "uk.housing.council_tax_band", + "equals": "E" + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "voa/council_tax/SCOTLAND/band_e", + "reduce": "any", + "household_conditions": [ + { + "variable": "council_tax_band", + "operator": "==", + "value": "E" + }, + { + "variable": "region", + "operator": "==", + "value": "SCOTLAND" + } + ], + "value_variable": "household_count", + "notes": "Scottish chargeable dwellings (CTAXBASE September 2025); uk-data files these under voa/council_tax/SCOTLAND/*." + }, + "axiom": { + "metric_name": "voa/council_tax/SCOTLAND/band_e", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "scotgov", + "source_measure_id": "band_e" + } + }, + { + "target_id": "voa.council_tax_stock.band_f", + "family": "council_tax_stock", + "geography_levels": [ + "region", + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count", + "filters": [ + { + "concept": "uk.housing.council_tax_band", + "equals": "F" + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "voa/council_tax/band_f", + "reduce": "any", + "household_conditions": [ + { + "variable": "council_tax_band", + "operator": "==", + "value": "F" + } + ], + "value_variable": "household_count", + "notes": "Dwelling stock proxied by households; one row per VOA geography (English regions at region level, Wales at country level) - the resolved geography binds the region filter (compute/council_tax.py:6-18). uk-data does not target VOA band I." + }, + "axiom": { + "metric_name": "voa/council_tax/band_f", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "voa", + "source_measure_id": "band_f" + } + }, + { + "target_id": "scotgov.council_tax_stock.band_f", + "family": "council_tax_stock", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count", + "filters": [ + { + "concept": "uk.housing.council_tax_band", + "equals": "F" + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "voa/council_tax/SCOTLAND/band_f", + "reduce": "any", + "household_conditions": [ + { + "variable": "council_tax_band", + "operator": "==", + "value": "F" + }, + { + "variable": "region", + "operator": "==", + "value": "SCOTLAND" + } + ], + "value_variable": "household_count", + "notes": "Scottish chargeable dwellings (CTAXBASE September 2025); uk-data files these under voa/council_tax/SCOTLAND/*." + }, + "axiom": { + "metric_name": "voa/council_tax/SCOTLAND/band_f", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "scotgov", + "source_measure_id": "band_f" + } + }, + { + "target_id": "voa.council_tax_stock.band_g", + "family": "council_tax_stock", + "geography_levels": [ + "region", + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count", + "filters": [ + { + "concept": "uk.housing.council_tax_band", + "equals": "G" + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "voa/council_tax/band_g", + "reduce": "any", + "household_conditions": [ + { + "variable": "council_tax_band", + "operator": "==", + "value": "G" + } + ], + "value_variable": "household_count", + "notes": "Dwelling stock proxied by households; one row per VOA geography (English regions at region level, Wales at country level) - the resolved geography binds the region filter (compute/council_tax.py:6-18). uk-data does not target VOA band I." + }, + "axiom": { + "metric_name": "voa/council_tax/band_g", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "voa", + "source_measure_id": "band_g" + } + }, + { + "target_id": "scotgov.council_tax_stock.band_g", + "family": "council_tax_stock", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count", + "filters": [ + { + "concept": "uk.housing.council_tax_band", + "equals": "G" + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "voa/council_tax/SCOTLAND/band_g", + "reduce": "any", + "household_conditions": [ + { + "variable": "council_tax_band", + "operator": "==", + "value": "G" + }, + { + "variable": "region", + "operator": "==", + "value": "SCOTLAND" + } + ], + "value_variable": "household_count", + "notes": "Scottish chargeable dwellings (CTAXBASE September 2025); uk-data files these under voa/council_tax/SCOTLAND/*." + }, + "axiom": { + "metric_name": "voa/council_tax/SCOTLAND/band_g", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "scotgov", + "source_measure_id": "band_g" + } + }, + { + "target_id": "voa.council_tax_stock.band_h", + "family": "council_tax_stock", + "geography_levels": [ + "region", + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count", + "filters": [ + { + "concept": "uk.housing.council_tax_band", + "equals": "H" + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "voa/council_tax/band_h", + "reduce": "any", + "household_conditions": [ + { + "variable": "council_tax_band", + "operator": "==", + "value": "H" + } + ], + "value_variable": "household_count", + "notes": "Dwelling stock proxied by households; one row per VOA geography (English regions at region level, Wales at country level) - the resolved geography binds the region filter (compute/council_tax.py:6-18). uk-data does not target VOA band I." + }, + "axiom": { + "metric_name": "voa/council_tax/band_h", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "voa", + "source_measure_id": "band_h" + } + }, + { + "target_id": "scotgov.council_tax_stock.band_h", + "family": "council_tax_stock", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count", + "filters": [ + { + "concept": "uk.housing.council_tax_band", + "equals": "H" + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "voa/council_tax/SCOTLAND/band_h", + "reduce": "any", + "household_conditions": [ + { + "variable": "council_tax_band", + "operator": "==", + "value": "H" + }, + { + "variable": "region", + "operator": "==", + "value": "SCOTLAND" + } + ], + "value_variable": "household_count", + "notes": "Scottish chargeable dwellings (CTAXBASE September 2025); uk-data files these under voa/council_tax/SCOTLAND/*." + }, + "axiom": { + "metric_name": "voa/council_tax/SCOTLAND/band_h", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "scotgov", + "source_measure_id": "band_h" + } + }, + { + "target_id": "voa.council_tax_stock.total", + "family": "council_tax_stock", + "geography_levels": [ + "region", + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count" + }, + "bindings": { + "policyengine": { + "metric_name": "voa/council_tax/total", + "reduce": "any", + "household_conditions": [ + { + "variable": "household_num_benunits", + "operator": ">=", + "value": 0 + } + ], + "value_variable": "household_count", + "notes": "Dwelling stock proxied by households; one row per VOA geography (English regions at region level, Wales at country level) - the resolved geography binds the region filter (compute/council_tax.py:6-18). uk-data does not target VOA band I." + }, + "axiom": { + "metric_name": "voa/council_tax/total", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "voa", + "source_measure_id": "all_properties" + } + }, + { + "target_id": "scotgov.council_tax_stock.total", + "family": "council_tax_stock", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.household.count" + }, + "bindings": { + "policyengine": { + "metric_name": "voa/council_tax/SCOTLAND/total", + "reduce": "any", + "household_conditions": [ + { + "variable": "household_num_benunits", + "operator": ">=", + "value": 0 + }, + { + "variable": "region", + "operator": "==", + "value": "SCOTLAND" + } + ], + "value_variable": "household_count", + "notes": "Scottish chargeable dwellings (CTAXBASE September 2025); uk-data files these under voa/council_tax/SCOTLAND/*." + }, + "axiom": { + "metric_name": "voa/council_tax/SCOTLAND/total", + "status": "pending", + "value_rule": "uk.household.count" + } + }, + "ledger_selector": { + "source_name": "scotgov", + "source_measure_id": "total" + } + }, + { + "target_id": "scotgov.scottish_child_payment_spending", + "family": "scotgov_social_security", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.benefits.scottish_child_payment.amount" + }, + "bindings": { + "policyengine": { + "metric_name": "sss/scottish_child_payment", + "value_variable": "scottish_child_payment", + "from_entity": "person", + "map_to": "household", + "notes": "uk-data's 3%-per-year extrapolation beyond the budget horizon is a populace-side declaration; the facts are the published budget lines." + }, + "axiom": { + "metric_name": "sss/scottish_child_payment", + "status": "pending", + "value_rule": "uk.benefits.scottish_child_payment.amount" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "scotgov", + "source_concept": "scotgov.social_security_assistance_spending", + "dimension_values": { + "social_security_line": "scottish_child_payment" + } + } + }, + { + "target_id": "ons.savings_interest_income", + "family": "ons_national_accounts", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.income.savings_interest.amount" + }, + "bindings": { + "policyengine": { + "metric_name": "ons/savings_interest_income", + "value_variable": "savings_interest_income", + "from_entity": "person", + "map_to": "household", + "notes": "uk-data holds the last actual flat for later years - a populace-side declaration (sources/ons_savings.py:39-44)." + }, + "axiom": { + "metric_name": "ons/savings_interest_income", + "status": "pending", + "value_rule": "uk.income.savings_interest.amount" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.ukea_haxv" + } + }, + { + "target_id": "ons.public_sector_employment", + "family": "ons_employment", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.employment.sector", + "equals": "public" + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "ons/public_sector_employment", + "filters": [ + { + "variable": "employment_sector", + "equals": "PUBLIC" + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "ons/public_sector_employment", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_measure_id": "total_public_sector" + } + }, + { + "target_id": "ons.land.land_value", + "family": "ons_land", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.wealth.land_value.amount" + }, + "bindings": { + "policyengine": { + "metric_name": "ons/land_value", + "value_variable": "land_value", + "notes": "National balance sheet land series for the total_economy sector; uk-data carries the last estimate flat to later years (populace-side declaration, sources/_land.py:52-73)." + }, + "axiom": { + "metric_name": "ons/land_value", + "status": "pending", + "value_rule": "uk.wealth.land_value.amount" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.e44r" + } + }, + { + "target_id": "ons.land.household_land_value", + "family": "ons_land", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.wealth.household_land_value.amount" + }, + "bindings": { + "policyengine": { + "metric_name": "ons/household_land_value", + "value_variable": "household_land_value", + "notes": "National balance sheet land series for the households_and_npish sector; uk-data carries the last estimate flat to later years (populace-side declaration, sources/_land.py:52-73)." + }, + "axiom": { + "metric_name": "ons/household_land_value", + "status": "pending", + "value_rule": "uk.wealth.household_land_value.amount" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.e44n" + } + }, + { + "target_id": "ons.land.corporate_land_value", + "family": "ons_land", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "household", + "concept": "uk.wealth.corporate_land_value.amount" + }, + "bindings": { + "policyengine": { + "metric_name": "ons/corporate_land_value", + "value_variable": "corporate_land_value", + "notes": "National balance sheet land series for the non_financial_corporations sector; uk-data carries the last estimate flat to later years (populace-side declaration, sources/_land.py:52-73)." + }, + "axiom": { + "metric_name": "ons/corporate_land_value", + "status": "pending", + "value_rule": "uk.wealth.corporate_land_value.amount" + } + }, + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.e43b" + } + }, + { + "target_id": "slc.repayments.devolved_total", + "family": "slc_repayments", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.finance.student_loan_repayments.amount" + }, + "bindings": { + "policyengine": { + "metric_name": "slc/student_loan_repayment/devolved", + "value_variable": "student_loan_repayment", + "from_entity": "person", + "map_to": "household", + "notes": "One fact per devolved country (Scotland, Wales, Northern Ireland); the resolved geography binds the model country filter (compute/other.py:116-137)." + }, + "axiom": { + "metric_name": "slc/student_loan_repayment/devolved", + "status": "pending", + "value_rule": "uk.finance.student_loan_repayments.amount" + } + }, + "ledger_selector": { + "source_name": "slc", + "source_concept": "slc.student_loan_net_repayments_total" + } + }, + { + "target_id": "slc.repayments.england_total_higher_education", + "family": "slc_repayments", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.finance.student_loan_repayments.amount", + "filters": [ + { + "concept": "uk.geography.country", + "equals": "england" + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "slc/student_loan_repayment/england", + "value_variable": "student_loan_repayment", + "from_entity": "person", + "map_to": "household", + "filters": [ + { + "variable": "country", + "equals": "ENGLAND" + } + ], + "source_lines": [ + "total_higher_education" + ] + }, + "axiom": { + "metric_name": "slc/student_loan_repayment/england", + "status": "pending", + "value_rule": "uk.finance.student_loan_repayments.amount" + } + }, + "ledger_selector": { + "source_name": "slc", + "groupby_dimension": "slc.repayment_plan", + "source_measure_id": [ + "total_higher_education" + ] + } + }, + { + "target_id": "slc.repayments.england_plan_1", + "family": "slc_repayments", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.finance.student_loan_repayments.amount", + "filters": [ + { + "concept": "uk.geography.country", + "equals": "england" + }, + { + "concept": "uk.finance.student_loan_plan", + "equals": "plan_1" + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "slc/student_loan_repayment/england/plan_1", + "value_variable": "student_loan_repayment", + "from_entity": "person", + "map_to": "household", + "filters": [ + { + "variable": "country", + "equals": "ENGLAND" + }, + { + "variable": "student_loan_plan", + "equals": "PLAN_1" + } + ], + "source_lines": [ + "plan_1" + ] + }, + "axiom": { + "metric_name": "slc/student_loan_repayment/england/plan_1", + "status": "pending", + "value_rule": "uk.finance.student_loan_repayments.amount" + } + }, + "ledger_selector": { + "source_name": "slc", + "groupby_dimension": "slc.repayment_plan", + "source_measure_id": [ + "plan_1" + ] + } + }, + { + "target_id": "slc.repayments.england_plan_2", + "family": "slc_repayments", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.finance.student_loan_repayments.amount", + "filters": [ + { + "concept": "uk.geography.country", + "equals": "england" + }, + { + "concept": "uk.finance.student_loan_plan", + "equals": "plan_2" + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "slc/student_loan_repayment/england/plan_2", + "value_variable": "student_loan_repayment", + "from_entity": "person", + "map_to": "household", + "filters": [ + { + "variable": "country", + "equals": "ENGLAND" + }, + { + "variable": "student_loan_plan", + "equals": "PLAN_2" + } + ], + "source_lines": [ + "plan_2_full_time", + "plan_2_part_time" + ], + "notes": "Publisher splits full-time/part-time (and masters/doctoral) products the model does not distinguish; the listed source lines sum to this target (compute/other.py:116-137)." + }, + "axiom": { + "metric_name": "slc/student_loan_repayment/england/plan_2", + "status": "pending", + "value_rule": "uk.finance.student_loan_repayments.amount" + } + }, + "ledger_selector": { + "source_name": "slc", + "groupby_dimension": "slc.repayment_plan", + "source_measure_id": [ + "plan_2_full_time", + "plan_2_part_time" + ] + } + }, + { + "target_id": "slc.repayments.england_postgraduate", + "family": "slc_repayments", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.finance.student_loan_repayments.amount", + "filters": [ + { + "concept": "uk.geography.country", + "equals": "england" + }, + { + "concept": "uk.finance.student_loan_plan", + "equals": "postgraduate" + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "slc/student_loan_repayment/england/postgraduate", + "value_variable": "student_loan_repayment", + "from_entity": "person", + "map_to": "household", + "filters": [ + { + "variable": "country", + "equals": "ENGLAND" + }, + { + "variable": "student_loan_plan", + "equals": "POSTGRADUATE" + } + ], + "source_lines": [ + "plan_3_postgraduate_masters", + "plan_3_postgraduate_doctoral" + ], + "notes": "Publisher splits full-time/part-time (and masters/doctoral) products the model does not distinguish; the listed source lines sum to this target (compute/other.py:116-137)." + }, + "axiom": { + "metric_name": "slc/student_loan_repayment/england/postgraduate", + "status": "pending", + "value_rule": "uk.finance.student_loan_repayments.amount" + } + }, + "ledger_selector": { + "source_name": "slc", + "groupby_dimension": "slc.repayment_plan", + "source_measure_id": [ + "plan_3_postgraduate_masters", + "plan_3_postgraduate_doctoral" + ] + } + }, + { + "target_id": "slc.repayments.england_plan_5", + "family": "slc_repayments", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.finance.student_loan_repayments.amount", + "filters": [ + { + "concept": "uk.geography.country", + "equals": "england" + }, + { + "concept": "uk.finance.student_loan_plan", + "equals": "plan_5" + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "slc/student_loan_repayment/england/plan_5", + "value_variable": "student_loan_repayment", + "from_entity": "person", + "map_to": "household", + "filters": [ + { + "variable": "country", + "equals": "ENGLAND" + }, + { + "variable": "student_loan_plan", + "equals": "PLAN_5" + } + ], + "source_lines": [ + "plan_5_full_time", + "plan_5_part_time" + ], + "notes": "Publisher splits full-time/part-time (and masters/doctoral) products the model does not distinguish; the listed source lines sum to this target (compute/other.py:116-137)." + }, + "axiom": { + "metric_name": "slc/student_loan_repayment/england/plan_5", + "status": "pending", + "value_rule": "uk.finance.student_loan_repayments.amount" + } + }, + "ledger_selector": { + "source_name": "slc", + "groupby_dimension": "slc.repayment_plan", + "source_measure_id": [ + "plan_5_full_time", + "plan_5_part_time" + ] + } + }, + { + "target_id": "slc.borrowers.plan_2_above_threshold", + "family": "slc_borrowers", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count" + }, + "bindings": { + "policyengine": { + "metric_name": "slc/plan_2_borrowers_above_threshold", + "filters": [ + { + "variable": "student_loan_plan", + "equals": "PLAN_2" + }, + { + "variable": "country", + "equals": "ENGLAND" + }, + { + "variable": "student_loan_repayments", + "operator": ">", + "value": 0 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household", + "notes": "England borrowers on this plan earning above the repayment threshold (proxied by positive repayments, matching what the FRS captures via PAYE; compute/other.py:77-96)." + }, + "axiom": { + "metric_name": "slc/plan_2_borrowers_above_threshold", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "slc", + "source_concept": "slc.student_loan_borrowers", + "dimension_values": { + "row_group": "Higher education total", + "repayment_plan": "plan_2", + "borrower_status": "above_repayment_threshold" + } + } + }, + { + "target_id": "slc.borrowers.plan_2_liable", + "family": "slc_borrowers", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count" + }, + "bindings": { + "policyengine": { + "metric_name": "slc/plan_2_borrowers_liable", + "filters": [ + { + "variable": "student_loan_plan", + "equals": "PLAN_2" + }, + { + "variable": "country", + "equals": "ENGLAND" + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household", + "notes": "England borrowers on this plan liable to repay, including below-threshold holders (compute/other.py:99-113)." + }, + "axiom": { + "metric_name": "slc/plan_2_borrowers_liable", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "slc", + "source_concept": "slc.student_loan_borrowers", + "dimension_values": { + "row_group": "Higher education total", + "repayment_plan": "plan_2", + "borrower_status": "liable_to_repay" + } + } + }, + { + "target_id": "slc.borrowers.plan_5_above_threshold", + "family": "slc_borrowers", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count" + }, + "bindings": { + "policyengine": { + "metric_name": "slc/plan_5_borrowers_above_threshold", + "filters": [ + { + "variable": "student_loan_plan", + "equals": "PLAN_5" + }, + { + "variable": "country", + "equals": "ENGLAND" + }, + { + "variable": "student_loan_repayments", + "operator": ">", + "value": 0 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household", + "notes": "England borrowers on this plan earning above the repayment threshold (proxied by positive repayments, matching what the FRS captures via PAYE; compute/other.py:77-96)." + }, + "axiom": { + "metric_name": "slc/plan_5_borrowers_above_threshold", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "slc", + "source_concept": "slc.student_loan_borrowers", + "dimension_values": { + "row_group": "Higher education total", + "repayment_plan": "plan_5", + "borrower_status": "above_repayment_threshold" + } + } + }, + { + "target_id": "slc.borrowers.plan_5_liable", + "family": "slc_borrowers", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count" + }, + "bindings": { + "policyengine": { + "metric_name": "slc/plan_5_borrowers_liable", + "filters": [ + { + "variable": "student_loan_plan", + "equals": "PLAN_5" + }, + { + "variable": "country", + "equals": "ENGLAND" + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household", + "notes": "England borrowers on this plan liable to repay, including below-threshold holders (compute/other.py:99-113)." + }, + "axiom": { + "metric_name": "slc/plan_5_borrowers_liable", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "assertion_policy": "allow_source_projection", + "ledger_selector": { + "source_name": "slc", + "source_concept": "slc.student_loan_borrowers", + "dimension_values": { + "row_group": "Higher education total", + "repayment_plan": "plan_5", + "borrower_status": "liable_to_repay" + } + } + }, + { + "target_id": "slc.support.maintenance_loan_recipients", + "family": "slc_student_support", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.benefits.student_support.maintenance_loan.amount", + "operator": ">", + "value": 0 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "slc/maintenance_loan_recipients", + "filters": [ + { + "variable": "maintenance_loan", + "operator": ">", + "value": 0 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "slc/maintenance_loan_recipients", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "slc", + "source_concept": "slc.maintenance_loan_recipients" + } + }, + { + "target_id": "slc.support.maintenance_loan_spend", + "family": "slc_student_support", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.benefits.student_support.maintenance_loan.amount" + }, + "bindings": { + "policyengine": { + "metric_name": "slc/maintenance_loan_spend", + "value_variable": "maintenance_loan", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "slc/maintenance_loan_spend", + "status": "pending", + "value_rule": "uk.benefits.student_support.maintenance_loan.amount" + } + }, + "ledger_selector": { + "source_name": "slc", + "source_concept": "slc.maintenance_loan_amount_paid" + } + }, + { + "target_id": "slc.support.parents_learning_allowance_recipients", + "family": "slc_student_support", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.benefits.student_support.parents_learning_allowance.amount", + "operator": ">", + "value": 0 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "slc/parents_learning_allowance_recipients", + "filters": [ + { + "variable": "parents_learning_allowance", + "operator": ">", + "value": 0 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "slc/parents_learning_allowance_recipients", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "slc", + "source_concept": "slc.targeted_support_recipients", + "dimension_values": { + "student_support_product": "parents_learning_allowance" + } + } + }, + { + "target_id": "slc.support.parents_learning_allowance_spend", + "family": "slc_student_support", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.benefits.student_support.parents_learning_allowance.amount" + }, + "bindings": { + "policyengine": { + "metric_name": "slc/parents_learning_allowance_spend", + "value_variable": "parents_learning_allowance", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "slc/parents_learning_allowance_spend", + "status": "pending", + "value_rule": "uk.benefits.student_support.parents_learning_allowance.amount" + } + }, + "ledger_selector": { + "source_name": "slc", + "source_concept": "slc.targeted_support_amount_awarded", + "dimension_values": { + "student_support_product": "parents_learning_allowance" + } + } + }, + { + "target_id": "slc.support.adult_dependants_grant_recipients", + "family": "slc_student_support", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.person.count", + "filters": [ + { + "concept": "uk.benefits.student_support.adult_dependants_grant.amount", + "operator": ">", + "value": 0 + } + ] + }, + "bindings": { + "policyengine": { + "metric_name": "slc/adult_dependants_grant_recipients", + "filters": [ + { + "variable": "adult_dependants_grant", + "operator": ">", + "value": 0 + } + ], + "value_variable": "person_count", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "slc/adult_dependants_grant_recipients", + "status": "pending", + "value_rule": "uk.person.count" + } + }, + "ledger_selector": { + "source_name": "slc", + "source_concept": "slc.targeted_support_recipients", + "dimension_values": { + "student_support_product": "adult_dependants_grant" + } + } + }, + { + "target_id": "slc.support.adult_dependants_grant_spend", + "family": "slc_student_support", + "geography_levels": [ + "country" + ], + "measurement": { + "entity": "person", + "map_to": "household", + "concept": "uk.benefits.student_support.adult_dependants_grant.amount" + }, + "bindings": { + "policyengine": { + "metric_name": "slc/adult_dependants_grant_spend", + "value_variable": "adult_dependants_grant", + "from_entity": "person", + "map_to": "household" + }, + "axiom": { + "metric_name": "slc/adult_dependants_grant_spend", + "status": "pending", + "value_rule": "uk.benefits.student_support.adult_dependants_grant.amount" + } + }, + "ledger_selector": { + "source_name": "slc", + "source_concept": "slc.targeted_support_amount_awarded", + "dimension_values": { + "student_support_product": "adult_dependants_grant" + } + } + } + ] +} diff --git a/packages/microcosm-build/tests/test_country_spec.py b/packages/microcosm-build/tests/test_country_spec.py index b533aeeca..d92d4d5c8 100644 --- a/packages/microcosm-build/tests/test_country_spec.py +++ b/packages/microcosm-build/tests/test_country_spec.py @@ -326,6 +326,7 @@ def test_uk_package_loads(self) -> None: "release_input_coverage_manifest.json", "was_wealth_support_bounds.json", "uk_local_target_census.json", + "uk_national_targets.json", ) diff --git a/packages/microcosm-build/tests/test_uk_national_targets.py b/packages/microcosm-build/tests/test_uk_national_targets.py new file mode 100644 index 000000000..b29c97316 --- /dev/null +++ b/packages/microcosm-build/tests/test_uk_national_targets.py @@ -0,0 +1,128 @@ +"""Guarantees for the UK national calibration contract resource. + +``uk/uk_national_targets.json`` is the consumer-side selection contract over +Chronicle facts (chronicle#166 ruling: contracts live in Microcosm; Chronicle +is facts-only). Values resolve from a Chronicle consumer artifact at build +time — the resource itself must stay value-free, hook-free, and closed-world +on its declarative counterfactual vocabulary. Compilation is microcosm#622. +""" + +from __future__ import annotations + +import json +from collections.abc import Mapping +from importlib import resources as importlib_resources + +FORBIDDEN_VALUE_KEYS = {"aggregation", "operation", "registry", "target_value", "value"} +FORBIDDEN_RUNTIME_KEYS = { + "callable", + "command", + "execute", + "executable", + "function", + "import", + "imports", + "module", + "python_code", + "runtime_code", + "script", + "solver", +} +BINDING_KINDS = { + "input_substitution_counterfactual", + "parameter_gated_threshold", + "baseline_flag_crosstab", +} +PROJECTION_FAMILIES = {"obr", "slc_borrowers", "scotgov_social_security"} + + +def _load() -> dict: + payload = ( + importlib_resources.files("microcosm.build.uk") + .joinpath("uk_national_targets.json") + .read_text() + ) + return json.loads(payload) + + +def _is_filter_predicate(node: Mapping) -> bool: + return "value" in node and "operator" in node and ( + "concept" in node or "variable" in node + ) + + +def _carried_forbidden_keys(node, *, in_defaults: bool = False) -> set[str]: + carried: set[str] = set() + if isinstance(node, Mapping): + forbidden = set(FORBIDDEN_VALUE_KEYS | FORBIDDEN_RUNTIME_KEYS) + if _is_filter_predicate(node): + forbidden.discard("value") + if in_defaults: + forbidden.discard("operation") + carried.update(forbidden.intersection(node)) + for child in node.values(): + carried.update(_carried_forbidden_keys(child)) + elif isinstance(node, (list, tuple)): + for child in node: + carried.update(_carried_forbidden_keys(child)) + return carried + + +def test_uk_national_targets_is_registered_in_the_country_package(): + package = json.loads( + importlib_resources.files("microcosm.build.uk") + .joinpath("country_package.json") + .read_text() + ) + + assert "uk_national_targets.json" in package["resources"] + + +def test_uk_national_targets_shape_and_accounting(): + resource = _load() + + assert resource["country"] == "uk" + assert resource["allowed_value_operations"] == ["identity"] + assert len(resource["targets"]) == 186 + + parity = resource["registry_parity"] + assert parity["pinned_ref"] == "ebf733c" + assert parity["mapped_rows"] + parity["excluded_rows"] == parity["registry_rows"] + assert len(parity["mapped"]) == parity["mapped_rows"] + assert len(parity["excluded"]) == parity["excluded_rows"] + mapped_target_ids = set(parity["mapped"].values()) + declared_target_ids = {target["target_id"] for target in resource["targets"]} + assert mapped_target_ids <= declared_target_ids + + +def test_uk_national_targets_are_value_free_and_hook_free(): + resource = _load() + + carried = _carried_forbidden_keys( + {key: value for key, value in resource.items() if key != "resolution_defaults"} + ) + carried |= _carried_forbidden_keys( + resource["resolution_defaults"], in_defaults=True + ) + assert not carried, sorted(carried) + assert resource["resolution_defaults"]["operation"] == "sum" + + +def test_uk_national_targets_declare_selectors_and_closed_world_kinds(): + resource = _load() + + metric_names: list[str] = [] + for target in resource["targets"]: + assert target["ledger_selector"], target["target_id"] + assert "assertion" not in target["ledger_selector"], target["target_id"] + binding = target["bindings"]["policyengine"] + metric_names.append(binding["metric_name"]) + kind = binding.get("kind") + assert kind is None or kind in BINDING_KINDS, target["target_id"] + if target["family"] in PROJECTION_FAMILIES: + assert target.get("assertion_policy") == "allow_source_projection", ( + target["target_id"] + ) + else: + assert "assertion_policy" not in target, target["target_id"] + assert len(metric_names) == len(set(metric_names)) From d9fa5f6ece4116efe70e3084baef3ff6ac0a8e1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20Juaristi?= <127882282+juaristi22@users.noreply.github.com> Date: Tue, 18 Aug 2026 17:57:27 +0200 Subject: [PATCH 02/10] Allowlist the UK contract's incumbent-name accounting in the live-tree guard The registry-parity accounting must name policyengine-uk-data (651 rows at pinned ref ebf733c); same sha-locked historical-reference class as the parity references already allowlisted. Co-Authored-By: Claude Fable 5 --- packages/microcosm-build/tests/test_us_plan.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/microcosm-build/tests/test_us_plan.py b/packages/microcosm-build/tests/test_us_plan.py index 9d4a66dfb..eae2d039c 100644 --- a/packages/microcosm-build/tests/test_us_plan.py +++ b/packages/microcosm-build/tests/test_us_plan.py @@ -984,6 +984,11 @@ def test_no_incumbent_data_package_references_in_live_tree(self) -> None: # never import or execute the retired data package. "packages/microcosm-build/src/microcosm/build/uk/efrs_parity_reference.json", "packages/microcosm-build/src/microcosm/build/uk/hmrc_income_source_stages.json", + # The UK national contract's registry-parity accounting names the + # retired data package by necessity: 651 rows at pinned ref ebf733c + # = 609 mapped + 42 signed exclusions + 3 unmapped declarations. + # A sha-locked historical reference — nothing imported or executed. + "packages/microcosm-build/src/microcosm/build/uk/uk_national_targets.json", "packages/microcosm-build/src/microcosm/build/uk_runtime/parity_reference.py", # The HMRC source contract pins the licensed SPI/ODS input # identities, whose reviewed provenance names the archived data From 872d7a906ccecd2e3d2f9cfff1a781827b97fb47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20Juaristi?= <127882282+juaristi22@users.noreply.github.com> Date: Tue, 18 Aug 2026 17:57:27 +0200 Subject: [PATCH 03/10] Sign the contract's accounting closure and port the chronicle loader guarantees MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Registry parity gains unmapped_declarations (3 salary-sacrifice IT-relief targets whose incumbent rows are suppressed by a 410-Gone CSV at the pin) and accounting_notes (cross-level duplicate names; the 15 two-child-limit rows are 2026-only, so the incumbent surface is 636 at 2025 vs 651 at 2026 — the #622 Fixture-B input). The parity test flips from subset to exact closure. geography_levels canonicalized country-first on the 9 VOA targets; issue citations normalized to their repo namespaces; tests now pin target_id uniqueness, closed-world selector/binding vocabularies, per-kind required fields, two-level reduce, and the CGT name equality with UK_CGT_TARGET_SPECS. Co-Authored-By: Claude Fable 5 --- .../build/uk/uk_national_targets.json | 112 ++++++------ .../tests/test_uk_national_targets.py | 161 +++++++++++++++++- 2 files changed, 219 insertions(+), 54 deletions(-) diff --git a/packages/microcosm-build/src/microcosm/build/uk/uk_national_targets.json b/packages/microcosm-build/src/microcosm/build/uk/uk_national_targets.json index 6ed2e332f..29eeea668 100644 --- a/packages/microcosm-build/src/microcosm/build/uk/uk_national_targets.json +++ b/packages/microcosm-build/src/microcosm/build/uk/uk_national_targets.json @@ -1,7 +1,7 @@ { "schema_version": 1, "country": "uk", - "description": "UK national calibration contract: value-free target declarations over Chronicle facts. Selection contracts live in Microcosm per the chronicle#166 ruling (2026-08-13): Chronicle is a facts-only layer; Microcosm owns which facts are targets, how they bind to the model, and the active subset. Observed values resolve from a hash-pinned Chronicle consumer-facts artifact at build time (identity only). Compilation to TargetSpec rows, the UK mapping module, and the metric providers for the declarative counterfactual kinds are microcosm#622; the calibration seam is microcosm#623.", + "description": "UK national calibration contract: value-free target declarations over Chronicle facts. Selection contracts live in Microcosm per the chronicle#166 ruling (2026-08-13): Chronicle is a facts-only layer; Microcosm owns which facts are targets, how they bind to the model, and the active subset. Observed values resolve from a hash-pinned Chronicle consumer-facts artifact at build time (identity only). Compilation to TargetSpec rows, the UK mapping module, and the metric providers for the declarative counterfactual kinds are microcosm#622; the calibration seam is microcosm#623. The ledger_selector vocabulary is shared with typed LedgerTargetReference rows; this contract's dimension_values, groupby_dimension, and list-form dimensions extend it with the chronicle#164 selector semantics implemented in ledger_targets.py. groupby_dimension is the chronicle spelling of the fact's layout.groupby_dimension.", "allowed_value_operations": [ "identity" ], @@ -628,28 +628,28 @@ "voa/council_tax/YORKSHIRE/total": "voa.council_tax_stock.total" }, "excluded": { - "dwp/benefit_cap_total_reduction": "The GBP 320.9m total reduction is uk-data's computed annualization of a monthly figure - excluded per the facts-only ADR (#139).", - "hmrc/capital_gains_band_100000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", - "hmrc/capital_gains_band_1000000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", - "hmrc/capital_gains_band_12300": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", - "hmrc/capital_gains_band_2000000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", - "hmrc/capital_gains_band_25000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", - "hmrc/capital_gains_band_250000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", - "hmrc/capital_gains_band_50000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", - "hmrc/capital_gains_band_500000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", - "hmrc/capital_gains_band_5000000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", - "hmrc/cgt_taxpayers_band_100000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", - "hmrc/cgt_taxpayers_band_1000000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", - "hmrc/cgt_taxpayers_band_12300": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", - "hmrc/cgt_taxpayers_band_2000000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", - "hmrc/cgt_taxpayers_band_25000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", - "hmrc/cgt_taxpayers_band_250000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", - "hmrc/cgt_taxpayers_band_50000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", - "hmrc/cgt_taxpayers_band_500000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", - "hmrc/cgt_taxpayers_band_5000000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside populace#467.", + "dwp/benefit_cap_total_reduction": "The GBP 320.9m total reduction is uk-data's computed annualization of a monthly figure - excluded per the facts-only ADR (chronicle#139).", + "hmrc/capital_gains_band_100000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside microcosm#467.", + "hmrc/capital_gains_band_1000000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside microcosm#467.", + "hmrc/capital_gains_band_12300": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside microcosm#467.", + "hmrc/capital_gains_band_2000000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside microcosm#467.", + "hmrc/capital_gains_band_25000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside microcosm#467.", + "hmrc/capital_gains_band_250000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside microcosm#467.", + "hmrc/capital_gains_band_50000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside microcosm#467.", + "hmrc/capital_gains_band_500000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside microcosm#467.", + "hmrc/capital_gains_band_5000000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside microcosm#467.", + "hmrc/cgt_taxpayers_band_100000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside microcosm#467.", + "hmrc/cgt_taxpayers_band_1000000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside microcosm#467.", + "hmrc/cgt_taxpayers_band_12300": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside microcosm#467.", + "hmrc/cgt_taxpayers_band_2000000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside microcosm#467.", + "hmrc/cgt_taxpayers_band_25000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside microcosm#467.", + "hmrc/cgt_taxpayers_band_250000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside microcosm#467.", + "hmrc/cgt_taxpayers_band_50000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside microcosm#467.", + "hmrc/cgt_taxpayers_band_500000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside microcosm#467.", + "hmrc/cgt_taxpayers_band_5000000": "Banded CGT rows read uk-data's storage/capital_gains_size_distribution_hmrc.csv, which was never packaged (no publisher table pinned). Candidate follow-up alongside microcosm#467.", "hmrc/salary_sacrifice_contributions": "SPP Review 2025 base value (GBP 24bn); the pinned asset 404s with no Wayback snapshot - blocked until a source surfaces (checklist row).", - "housing/rent_private": "Computed rate x count products (PIPR mean rent / EHS mean weekly cost x unpinned tenure counts). The base facts are ported (#159); the product stays a populace-side declaration per the facts-only ADR.", - "housing/rent_social": "Computed rate x count products (PIPR mean rent / EHS mean weekly cost x unpinned tenure counts). The base facts are ported (#159); the product stays a populace-side declaration per the facts-only ADR.", + "housing/rent_private": "Computed rate x count products (PIPR mean rent / EHS mean weekly cost x unpinned tenure counts). The base facts are ported (chronicle#159); the product stays a populace-side declaration per the facts-only ADR.", + "housing/rent_social": "Computed rate x count products (PIPR mean rent / EHS mean weekly cost x unpinned tenure counts). The base facts are ported (chronicle#159); the product stays a populace-side declaration per the facts-only ADR.", "housing/total_mortgage": "No publisher source: uk-data cites the ONS rent bulletin, which carries no mortgage figure (policyengine-uk-data#453). Nearest sourced anchor is EHS AT1.7 all-mortgagors mean weekly housing costs.", "nts/households_no_vehicle": "DfT NTS facts are percent shares; uk-data targets household counts. Identity-only value resolution cannot scale a share into a count - populace derives the count targets (share x household total), following the US derived-CHIP precedent.", "nts/households_one_vehicle": "DfT NTS facts are percent shares; uk-data targets household counts. Identity-only value resolution cannot scale a share into a count - populace derives the count targets (share x household total), following the US derived-CHIP precedent.", @@ -665,11 +665,21 @@ "ons/household_land_value/WALES": "Regional household land values are uk-data's computed allocation (dwellings x average house price shares, sources/mhclg_regional_land.py) - no publisher regional land facts exist to port.", "ons/household_land_value/WEST_MIDLANDS": "Regional household land values are uk-data's computed allocation (dwellings x average house price shares, sources/mhclg_regional_land.py) - no publisher regional land facts exist to port.", "ons/household_land_value/YORKSHIRE": "Regional household land values are uk-data's computed allocation (dwellings x average house price shares, sources/mhclg_regional_land.py) - no publisher regional land facts exist to port.", - "ons/tenure_england_owned_outright": "England tenure counts come from an LA-grain workbook uk-data code-sums; ruled non-portable as national facts on #133 - moved to the wave-3 LA package (#134).", - "ons/tenure_england_owned_with_mortgage": "England tenure counts come from an LA-grain workbook uk-data code-sums; ruled non-portable as national facts on #133 - moved to the wave-3 LA package (#134).", - "ons/tenure_england_rented_privately": "England tenure counts come from an LA-grain workbook uk-data code-sums; ruled non-portable as national facts on #133 - moved to the wave-3 LA package (#134).", - "ons/tenure_england_social_rent": "England tenure counts come from an LA-grain workbook uk-data code-sums; ruled non-portable as national facts on #133 - moved to the wave-3 LA package (#134).", - "ons/tenure_england_total": "England tenure counts come from an LA-grain workbook uk-data code-sums; ruled non-portable as national facts on #133 - moved to the wave-3 LA package (#134)." + "ons/tenure_england_owned_outright": "England tenure counts come from an LA-grain workbook uk-data code-sums; ruled non-portable as national facts on chronicle#133 - moved to the wave-3 LA package (chronicle#134).", + "ons/tenure_england_owned_with_mortgage": "England tenure counts come from an LA-grain workbook uk-data code-sums; ruled non-portable as national facts on chronicle#133 - moved to the wave-3 LA package (chronicle#134).", + "ons/tenure_england_rented_privately": "England tenure counts come from an LA-grain workbook uk-data code-sums; ruled non-portable as national facts on chronicle#133 - moved to the wave-3 LA package (chronicle#134).", + "ons/tenure_england_social_rent": "England tenure counts come from an LA-grain workbook uk-data code-sums; ruled non-portable as national facts on chronicle#133 - moved to the wave-3 LA package (chronicle#134).", + "ons/tenure_england_total": "England tenure counts come from an LA-grain workbook uk-data code-sums; ruled non-portable as national facts on chronicle#133 - moved to the wave-3 LA package (chronicle#134)." + }, + "unmapped_declarations": { + "hmrc.salary_sacrifice.it_relief_basic_rate": "New declaration backed by chronicle#139 salary-sacrifice facts; the incumbent source CSV is 410-Gone at ebf733c and its rows were silently suppressed by the bare-except drop in build_loss_matrix.py:376-394.", + "hmrc.salary_sacrifice.it_relief_higher_rate": "New declaration backed by chronicle#139 salary-sacrifice facts; the incumbent source CSV is 410-Gone at ebf733c and its rows were silently suppressed by the bare-except drop in build_loss_matrix.py:376-394.", + "hmrc.salary_sacrifice.it_relief_additional_rate": "New declaration backed by chronicle#139 salary-sacrifice facts; the incumbent source CSV is 410-Gone at ebf733c and its rows were silently suppressed by the bare-except drop in build_loss_matrix.py:376-394." + }, + "accounting_notes": { + "cross_level_duplicate_names": "Name-only identity flattens two-level emissions for ons/uk_population, ons/scotland_children_under_16, and ons/scotland_babies_under_1.", + "two_child_limit_year_surface": "The 15 dwp/uc/two_child_limit/* rows are 2026-only; the incumbent effective surface is 636 at calibration year 2025 and 651 at 2026. This is microcosm#622 Fixture-B input because the incumbent cannot self-report the year-specific surface.", + "geography_level_order_canonicalization": "The 9 voa.council_tax_stock.* rows use country, region order to match the rest of the contract; consumers use membership only." } }, "targets": [ @@ -720,7 +730,7 @@ "value_variable": "ni_employee", "from_entity": "person", "map_to": "household", - "notes": "uk-data binds this EFO total-NI line to ni_employee only, while separate employee/employer/self-employed lines are also calibrated - suspected binding defect carried as-is for parity; adjudicate in populace#622." + "notes": "uk-data binds this EFO total-NI line to ni_employee only, while separate employee/employer/self-employed lines are also calibrated - suspected binding defect carried as-is for parity; adjudicate in microcosm#622." }, "axiom": { "metric_name": "obr/ni", @@ -1336,7 +1346,7 @@ "value_variable": "pip", "from_entity": "person", "map_to": "household", - "notes": "EFO line covers DLA and PIP combined; uk-data binds pip only - carried as-is for parity; adjudicate in populace#622." + "notes": "EFO line covers DLA and PIP combined; uk-data binds pip only - carried as-is for parity; adjudicate in microcosm#622." }, "axiom": { "metric_name": "obr/pip", @@ -1735,7 +1745,7 @@ "output_variable": "ni_employee", "from_entity": "person", "map_to": "household", - "notes": "NICs relief attributed to salary sacrifice (compute/income.py:59-68). uk-data's SPP-Review-based obr/salary_sacrifice_employee_ni_relief row (source lost) retires onto this hmrc-backed fact - vintage difference for the populace#622 parity gate." + "notes": "NICs relief attributed to salary sacrifice (compute/income.py:59-68). uk-data's SPP-Review-based obr/salary_sacrifice_employee_ni_relief row (source lost) retires onto this hmrc-backed fact - vintage difference for the microcosm#622 parity gate." }, "axiom": { "metric_name": "hmrc/salary_sacrifice_employee_nics_relief", @@ -1769,7 +1779,7 @@ "output_variable": "ni_employer", "from_entity": "person", "map_to": "household", - "notes": "NICs relief attributed to salary sacrifice (compute/income.py:59-68). uk-data's SPP-Review-based obr/salary_sacrifice_employer_ni_relief row (source lost) retires onto this hmrc-backed fact - vintage difference for the populace#622 parity gate." + "notes": "NICs relief attributed to salary sacrifice (compute/income.py:59-68). uk-data's SPP-Review-based obr/salary_sacrifice_employer_ni_relief row (source lost) retires onto this hmrc-backed fact - vintage difference for the microcosm#622 parity gate." }, "axiom": { "metric_name": "hmrc/salary_sacrifice_employer_nics_relief", @@ -2453,7 +2463,7 @@ "value_variable": "capital_gains", "from_entity": "person", "map_to": "household", - "notes": "Gains summed over people whose gains exceed the annual exempt amount (sources/hmrc_cgt.py:86-104). Also the single-homing successor for populace's UK_CGT_TARGET_SPECS (populace#622 item 6)." + "notes": "Gains summed over people whose gains exceed the annual exempt amount (sources/hmrc_cgt.py:86-104). Also the single-homing successor for populace's UK_CGT_TARGET_SPECS (microcosm#622 item 6)." }, "axiom": { "metric_name": "hmrc/capital_gains_total", @@ -2742,7 +2752,7 @@ "value_variable": "person_count", "from_entity": "person", "map_to": "household", - "notes": "uk-data binds the JSA claimant count to contributory JSA only (jsa_contrib) - carried as-is for parity; adjudicate in populace#622." + "notes": "uk-data binds the JSA claimant count to contributory JSA only (jsa_contrib) - carried as-is for parity; adjudicate in microcosm#622." }, "axiom": { "metric_name": "dwp/jsa_claimants", @@ -8133,8 +8143,8 @@ "target_id": "voa.council_tax_stock.band_a", "family": "council_tax_stock", "geography_levels": [ - "region", - "country" + "country", + "region" ], "measurement": { "entity": "household", @@ -8221,8 +8231,8 @@ "target_id": "voa.council_tax_stock.band_b", "family": "council_tax_stock", "geography_levels": [ - "region", - "country" + "country", + "region" ], "measurement": { "entity": "household", @@ -8309,8 +8319,8 @@ "target_id": "voa.council_tax_stock.band_c", "family": "council_tax_stock", "geography_levels": [ - "region", - "country" + "country", + "region" ], "measurement": { "entity": "household", @@ -8397,8 +8407,8 @@ "target_id": "voa.council_tax_stock.band_d", "family": "council_tax_stock", "geography_levels": [ - "region", - "country" + "country", + "region" ], "measurement": { "entity": "household", @@ -8485,8 +8495,8 @@ "target_id": "voa.council_tax_stock.band_e", "family": "council_tax_stock", "geography_levels": [ - "region", - "country" + "country", + "region" ], "measurement": { "entity": "household", @@ -8573,8 +8583,8 @@ "target_id": "voa.council_tax_stock.band_f", "family": "council_tax_stock", "geography_levels": [ - "region", - "country" + "country", + "region" ], "measurement": { "entity": "household", @@ -8661,8 +8671,8 @@ "target_id": "voa.council_tax_stock.band_g", "family": "council_tax_stock", "geography_levels": [ - "region", - "country" + "country", + "region" ], "measurement": { "entity": "household", @@ -8749,8 +8759,8 @@ "target_id": "voa.council_tax_stock.band_h", "family": "council_tax_stock", "geography_levels": [ - "region", - "country" + "country", + "region" ], "measurement": { "entity": "household", @@ -8837,8 +8847,8 @@ "target_id": "voa.council_tax_stock.total", "family": "council_tax_stock", "geography_levels": [ - "region", - "country" + "country", + "region" ], "measurement": { "entity": "household", diff --git a/packages/microcosm-build/tests/test_uk_national_targets.py b/packages/microcosm-build/tests/test_uk_national_targets.py index b29c97316..a7208c681 100644 --- a/packages/microcosm-build/tests/test_uk_national_targets.py +++ b/packages/microcosm-build/tests/test_uk_national_targets.py @@ -13,6 +13,8 @@ from collections.abc import Mapping from importlib import resources as importlib_resources +from microcosm.build.uk_runtime.fiscal_targets import UK_CGT_TARGET_SPECS + FORBIDDEN_VALUE_KEYS = {"aggregation", "operation", "registry", "target_value", "value"} FORBIDDEN_RUNTIME_KEYS = { "callable", @@ -34,6 +36,44 @@ "baseline_flag_crosstab", } PROJECTION_FAMILIES = {"obr", "slc_borrowers", "scotgov_social_security"} +SELECTOR_KEYS = { + "source_name", + "source_concept", + "source_measure_id", + "groupby_dimension", + "dimensions", + "dimension_values", +} +POLICYENGINE_BINDING_KEYS = { + "affected_flag_variable", + "band", + "band_period_factor", + "count_of", + "filters", + "folded_into", + "from_entity", + "gate_comparison", + "gate_parameter", + "gated_variable", + "groupby_variable", + "household_conditions", + "kind", + "map_to", + "metric_name", + "notes", + "output_delta", + "output_variable", + "reduce", + "source_lines", + "threshold_price_base_year", + "value_expression", + "value_variable", + "zeroed_input", +} +ASSERTION_POLICIES = {"allow_source_projection"} +BINDING_REDUCERS = {"any"} +PREDICATE_REDUCERS = {"any", "any_child_under", "count", "sum"} +PREDICATE_ENTITIES = {"person", "benunit", "household"} def _load() -> dict: @@ -91,8 +131,19 @@ def test_uk_national_targets_shape_and_accounting(): assert len(parity["mapped"]) == parity["mapped_rows"] assert len(parity["excluded"]) == parity["excluded_rows"] mapped_target_ids = set(parity["mapped"].values()) + unmapped_declarations = parity["unmapped_declarations"] + assert set(mapped_target_ids).isdisjoint(unmapped_declarations) declared_target_ids = {target["target_id"] for target in resource["targets"]} - assert mapped_target_ids <= declared_target_ids + assert mapped_target_ids | set(unmapped_declarations) == declared_target_ids + assert all(reason for reason in unmapped_declarations.values()) + assert len(mapped_target_ids) == 183 + + +def test_uk_national_targets_have_unique_target_ids(): + resource = _load() + + target_ids = [target["target_id"] for target in resource["targets"]] + assert len(target_ids) == len(set(target_ids)) def test_uk_national_targets_are_value_free_and_hook_free(): @@ -113,9 +164,12 @@ def test_uk_national_targets_declare_selectors_and_closed_world_kinds(): metric_names: list[str] = [] for target in resource["targets"]: - assert target["ledger_selector"], target["target_id"] - assert "assertion" not in target["ledger_selector"], target["target_id"] + selector = target["ledger_selector"] + assert selector, target["target_id"] + assert set(selector) <= SELECTOR_KEYS, target["target_id"] + assert "assertion" not in selector, target["target_id"] binding = target["bindings"]["policyengine"] + assert set(binding) <= POLICYENGINE_BINDING_KEYS, target["target_id"] metric_names.append(binding["metric_name"]) kind = binding.get("kind") assert kind is None or kind in BINDING_KINDS, target["target_id"] @@ -126,3 +180,104 @@ def test_uk_national_targets_declare_selectors_and_closed_world_kinds(): else: assert "assertion_policy" not in target, target["target_id"] assert len(metric_names) == len(set(metric_names)) + + +def test_uk_national_targets_declare_chronicle_loader_guarantees(): + resource = _load() + + for target in resource["targets"]: + selector = target["ledger_selector"] + if "dimension_values" in selector: + assert _valid_dimension_values(selector["dimension_values"]), ( + target["target_id"] + ) + if "dimensions" in selector: + dimensions = selector["dimensions"] + assert isinstance(dimensions, list), target["target_id"] + assert all(isinstance(name, str) and name for name in dimensions), ( + target["target_id"] + ) + + binding = target["bindings"]["policyengine"] + kind = binding.get("kind") + if kind == "input_substitution_counterfactual": + assert { + "zeroed_input", + "folded_into", + "output_variable", + "output_delta", + } <= set(binding), target["target_id"] + elif kind == "parameter_gated_threshold": + assert { + "gate_parameter", + "gated_variable", + "gate_comparison", + } <= set(binding), target["target_id"] + elif kind == "baseline_flag_crosstab": + assert {"affected_flag_variable", "count_of"} <= set(binding), ( + target["target_id"] + ) + + if "reduce" in binding: + assert binding["reduce"] in BINDING_REDUCERS, target["target_id"] + for field in ("filters", "household_conditions"): + for predicate in binding.get(field, ()): + if "reduce" in predicate: + assert predicate["reduce"] in PREDICATE_REDUCERS, ( + target["target_id"], + predicate, + ) + if "entity" in predicate: + assert predicate["entity"] in PREDICATE_ENTITIES, ( + target["target_id"], + predicate, + ) + + assertion_policy = target.get("assertion_policy") + if assertion_policy is not None: + assert assertion_policy in ASSERTION_POLICIES, target["target_id"] + + assert _target_by_id(resource, "obr.esa")["bindings"]["policyengine"][ + "value_expression" + ] == "esa_income + esa_contrib" + + +def test_uk_national_cgt_contract_names_match_runtime_specs(): + resource = _load() + + cgt_metric_names = { + target["bindings"]["policyengine"]["metric_name"] + for target in resource["targets"] + if target["target_id"].startswith("hmrc.cgt.") + } + + assert cgt_metric_names == {spec.name for spec in UK_CGT_TARGET_SPECS} + + +def _target_by_id(resource: Mapping, target_id: str) -> Mapping: + for target in resource["targets"]: + if target["target_id"] == target_id: + return target + raise AssertionError(f"missing target {target_id!r}") + + +def _valid_dimension_values(value: object) -> bool: + if not isinstance(value, Mapping): + return False + if not value: + return False + for key, expected in value.items(): + if not isinstance(key, str) or not key: + return False + if _is_dimension_scalar(expected): + continue + if isinstance(expected, list) and expected and all( + _is_dimension_scalar(item) for item in expected + ): + continue + return False + return True + + +def _is_dimension_scalar(value: object) -> bool: + return isinstance(value, str | int | float | bool) From e5f75056da25d8944e0bbef33872b0cea1b5fc65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20Juaristi?= <127882282+juaristi22@users.noreply.github.com> Date: Tue, 18 Aug 2026 17:57:58 +0200 Subject: [PATCH 04/10] Extend the ledger selector vocabulary with the chronicle selector semantics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _fact_matches_selector learns dimension_values (strict typed scalar equality, list membership, missing-dimension no-match — the chronicle#164 correction semantics), list-form dimensions selectors (exact order-insensitive name-set match; [] means the dimensionless total row), list-valued scalar keys (membership), and the chronicle spellings record_set_id / groupby_dimension as aliases for the layout fields. The mapping-form dimensions path is unchanged; unknown keys still raise. One resolver now serves the US references, the Belgian file, and all three re-homed UK contracts (#708). Co-Authored-By: Claude Fable 5 --- .../src/microcosm/build/ledger_targets.py | 46 +++++- .../tests/test_ledger_targets.py | 156 ++++++++++++++++++ 2 files changed, 199 insertions(+), 3 deletions(-) diff --git a/packages/microcosm-build/src/microcosm/build/ledger_targets.py b/packages/microcosm-build/src/microcosm/build/ledger_targets.py index afd110538..8e1ec4017 100644 --- a/packages/microcosm-build/src/microcosm/build/ledger_targets.py +++ b/packages/microcosm-build/src/microcosm/build/ledger_targets.py @@ -1040,9 +1040,17 @@ def _fact_matches_selector(fact: object, selector: Mapping[str, object]) -> bool if not _dimensions_match(fact, expected): return False continue + if key == "dimension_values": + if not _dimension_values_match(fact, expected): + return False + continue if expected is None or expected == "": continue candidates = _selector_candidates(fact, str(key)) + if isinstance(expected, (list, tuple)): + if not any(str(item) in candidates for item in expected): + return False + continue if str(expected) not in candidates: return False return True @@ -1084,9 +1092,9 @@ def _selector_candidates(fact: object, key: str) -> tuple[str, ...]: return (_str_at(fact, "geography", "id"),) if key == "entity_name": return (_str_at(fact, "entity", "name"),) - if key == "layout_record_set_id": + if key in {"record_set_id", "layout_record_set_id"}: return (_str_at(fact, "layout", "record_set_id"),) - if key == "layout_groupby_dimension": + if key in {"groupby_dimension", "layout_groupby_dimension"}: return (_str_at(fact, "layout", "groupby_dimension"),) if key == "layout_groupby_value_id": return (_str_at(fact, "layout", "groupby_value_id"),) @@ -1100,14 +1108,46 @@ def _selector_candidates(fact: object, key: str) -> tuple[str, ...]: def _dimensions_match(fact: object, expected: object) -> bool: + if isinstance(expected, list): + expected_names = {str(name) for name in expected} + dimension_names = {str(key) for key in _dimensions(fact)} + return dimension_names == expected_names if not isinstance(expected, Mapping): - raise ValueError("Ledger fact selector field 'dimensions' must be a mapping.") + raise ValueError( + "Ledger fact selector field 'dimensions' must be a mapping or list." + ) dimensions = {str(key): str(value) for key, value in _dimensions(fact).items()} return all( dimensions.get(str(key)) == str(value) for key, value in expected.items() ) +def _dimension_values_match(fact: object, expected: object) -> bool: + if not isinstance(expected, Mapping): + raise ValueError( + "Ledger fact selector field 'dimension_values' must be a mapping." + ) + dimensions = _dimensions(fact) + for key, expected_value in expected.items(): + if key not in dimensions: + return False + actual_value = dimensions[key] + if isinstance(expected_value, list): + if not any( + _strict_scalar_equal(actual_value, candidate) + for candidate in expected_value + ): + return False + continue + if not _strict_scalar_equal(actual_value, expected_value): + return False + return True + + +def _strict_scalar_equal(actual: object, expected: object) -> bool: + return type(actual) is type(expected) and actual == expected + + def _measure_concepts(fact: object) -> tuple[str, ...]: concepts = ( _str_at(fact, "measure", "concept"), diff --git a/packages/microcosm-build/tests/test_ledger_targets.py b/packages/microcosm-build/tests/test_ledger_targets.py index d3fbd1bb2..c07bd2f5c 100644 --- a/packages/microcosm-build/tests/test_ledger_targets.py +++ b/packages/microcosm-build/tests/test_ledger_targets.py @@ -699,6 +699,162 @@ def test__given_selector_matches_multiple_eligible_months__then_latest_month_is_ ) +class TestLedgerSelectorExtensions: + def test_dimension_values_use_strict_typed_equality(self) -> None: + reference = LedgerTargetReference( + name="typed dimension selector", + ledger_selector={"dimension_values": {"band": "5"}}, + entity="tax_unit", + measure="adjusted_gross_income", + period=2023, + family="irs_soi", + ) + + with pytest.raises(ValueError, match="did not match a Ledger fact selector"): + compile_ledger_target_references( + [_consumer_fact_row(dimensions={"band": 5})], + [reference], + country="us", + ) + + def test_dimension_values_accept_list_membership(self) -> None: + reference = LedgerTargetReference( + name="list dimension selector", + ledger_selector={"dimension_values": {"band": ["A", "B"]}}, + entity="tax_unit", + measure="adjusted_gross_income", + period=2023, + family="irs_soi", + ) + + registry = compile_ledger_target_references( + [_consumer_fact_row(dimensions={"band": "B"})], + [reference], + country="us", + ) + + assert registry.specs[0].name == "list dimension selector" + + def test_dimension_values_require_present_dimension(self) -> None: + reference = LedgerTargetReference( + name="missing dimension selector", + ledger_selector={"dimension_values": {"band": "A"}}, + entity="tax_unit", + measure="adjusted_gross_income", + period=2023, + family="irs_soi", + ) + + with pytest.raises(ValueError, match="did not match a Ledger fact selector"): + compile_ledger_target_references( + [_consumer_fact_row(dimensions={"income_range": "all"})], + [reference], + country="us", + ) + + def test_empty_dimensions_list_matches_dimensionless_fact(self) -> None: + reference = LedgerTargetReference( + name="dimensionless selector", + ledger_selector={"dimensions": []}, + entity="tax_unit", + measure="adjusted_gross_income", + period=2023, + family="irs_soi", + ) + + registry = compile_ledger_target_references( + [_consumer_fact_row(dimensions={})], + [reference], + country="us", + ) + + assert registry.specs[0].name == "dimensionless selector" + + def test_dimensions_list_matches_exact_name_set_order_insensitively(self) -> None: + fact = _consumer_fact_row(dimensions={"band": "A", "sex": "all"}) + reference = LedgerTargetReference( + name="dimension-name selector", + ledger_selector={"dimensions": ["sex", "band"]}, + entity="tax_unit", + measure="adjusted_gross_income", + period=2023, + family="irs_soi", + ) + missing_name = LedgerTargetReference( + name="partial dimension-name selector", + ledger_selector={"dimensions": ["band"]}, + entity="tax_unit", + measure="adjusted_gross_income", + period=2023, + family="irs_soi", + ) + + registry = compile_ledger_target_references([fact], [reference], country="us") + with pytest.raises(ValueError, match="did not match a Ledger fact selector"): + compile_ledger_target_references([fact], [missing_name], country="us") + + assert registry.specs[0].name == "dimension-name selector" + + def test_chronicle_layout_aliases_match_fact_layout(self) -> None: + reference = LedgerTargetReference( + name="layout alias selector", + ledger_selector={ + "record_set_id": "irs_soi.ty2023.table_1_1", + "groupby_dimension": "us:statutes/26/62#adjusted_gross_income", + }, + entity="tax_unit", + measure="adjusted_gross_income", + period=2023, + family="irs_soi", + ) + + registry = compile_ledger_target_references( + [_consumer_fact_row()], + [reference], + country="us", + ) + + assert registry.specs[0].name == "layout alias selector" + + def test_scalar_selector_accepts_list_expected_values(self) -> None: + reference = LedgerTargetReference( + name="list source measure selector", + ledger_selector={ + "source_measure_id": ["total_tax", "adjusted_gross_income"], + }, + entity="tax_unit", + measure="adjusted_gross_income", + period=2023, + family="irs_soi", + ) + + registry = compile_ledger_target_references( + [_consumer_fact_row()], + [reference], + country="us", + ) + + assert registry.specs[0].name == "list source measure selector" + + def test_us_mapping_dimensions_keep_subset_semantics(self) -> None: + reference = LedgerTargetReference( + name="mapping dimensions selector", + ledger_selector={"dimensions": {"income_range": "all"}}, + entity="tax_unit", + measure="adjusted_gross_income", + period=2023, + family="irs_soi", + ) + + registry = compile_ledger_target_references( + [_consumer_fact_row()], + [reference], + country="us", + ) + + assert registry.specs[0].name == "mapping dimensions selector" + + def test__given_selector_matches_only_future_year__then_compilation_fails() -> None: # Given reference = LedgerTargetReference( From 63ae0e9bb6f137c2b4f16c408a3d87a63730ce0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20Juaristi?= <127882282+juaristi22@users.noreply.github.com> Date: Tue, 18 Aug 2026 17:57:58 +0200 Subject: [PATCH 05/10] Declare the UK 2023 active subset as typed target references MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First activation of the national contract: 13 references (ISC census, the 10 ONS household-composition types, savings interest, public-sector employment) — the targets that compile fail-closed against chronicle facts at the 2023 base period under identity, with geography_level country appended as the activation row's geography. Deferred classes are enumerated for #622: 101 with no fact at or before 2023, 23 pending multi-fact sum resolution, 49 ambiguous across country-level geographies. Typed per the Belgian target_references.json convention; rich binding payloads stay in the contract, referenced via metadata.contract_target_id. Co-Authored-By: Claude Fable 5 --- .../microcosm/build/uk/country_package.json | 3 +- .../microcosm/build/uk/target_references.json | 244 ++++++++++++++++++ .../tests/test_country_spec.py | 5 +- .../tests/test_uk_target_references.py | 237 +++++++++++++++++ 4 files changed, 486 insertions(+), 3 deletions(-) create mode 100644 packages/microcosm-build/src/microcosm/build/uk/target_references.json create mode 100644 packages/microcosm-build/tests/test_uk_target_references.py diff --git a/packages/microcosm-build/src/microcosm/build/uk/country_package.json b/packages/microcosm-build/src/microcosm/build/uk/country_package.json index d0bb6ae16..7adb2917f 100644 --- a/packages/microcosm-build/src/microcosm/build/uk/country_package.json +++ b/packages/microcosm-build/src/microcosm/build/uk/country_package.json @@ -21,6 +21,7 @@ "release_input_coverage_manifest.json", "was_wealth_support_bounds.json", "uk_local_target_census.json", - "uk_national_targets.json" + "uk_national_targets.json", + "target_references.json" ] } diff --git a/packages/microcosm-build/src/microcosm/build/uk/target_references.json b/packages/microcosm-build/src/microcosm/build/uk/target_references.json new file mode 100644 index 000000000..568045c85 --- /dev/null +++ b/packages/microcosm-build/src/microcosm/build/uk/target_references.json @@ -0,0 +1,244 @@ +{ + "country": "uk", + "description": "UK active-subset Ledger target references for the national 2023 spine. Rows are generated from uk_national_targets.json: name is the contract target_id; ledger_selector is the contract selector plus geography_level country for the first national activation; entity is from_entity, then map_to, then household; measure is bindings.policyengine.metric_name; family is the contract family; period is 2023; metadata.contract_target_id points back to the contract row. Observed values stay in Ledger facts and resolve by identity only. Deferred classes are recorded in .codex-work/membership_report.json: no fact at or before 2023, multi-fact sum resolution pending, source-projection policy pending, country-level geography ambiguity, or missing/non-finite fact values.", + "allowed_value_operations": [ + "identity" + ], + "target_references": [ + { + "name": "isc.private_school_students", + "ledger_selector": { + "source_name": "isc", + "source_concept": "isc.pupils_at_member_schools", + "geography_level": "country" + }, + "entity": "person", + "measure": "obr/private_school_students", + "family": "isc", + "period": 2023, + "metadata": { + "contract_target_id": "isc.private_school_students" + } + }, + { + "name": "ons.household_composition.lone_households_under_65", + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.families_households_table7", + "groupby_dimension": "ons.household_type", + "dimension_values": { + "household_type": "lone_households_under_65" + }, + "geography_level": "country" + }, + "entity": "household", + "measure": "ons/lone_households_under_65", + "family": "ons_household_composition", + "period": 2023, + "metadata": { + "contract_target_id": "ons.household_composition.lone_households_under_65" + } + }, + { + "name": "ons.household_composition.lone_households_over_65", + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.families_households_table7", + "groupby_dimension": "ons.household_type", + "dimension_values": { + "household_type": "lone_households_over_65" + }, + "geography_level": "country" + }, + "entity": "household", + "measure": "ons/lone_households_over_65", + "family": "ons_household_composition", + "period": 2023, + "metadata": { + "contract_target_id": "ons.household_composition.lone_households_over_65" + } + }, + { + "name": "ons.household_composition.unrelated_adult_households", + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.families_households_table7", + "groupby_dimension": "ons.household_type", + "dimension_values": { + "household_type": "unrelated_adult_households" + }, + "geography_level": "country" + }, + "entity": "household", + "measure": "ons/unrelated_adult_households", + "family": "ons_household_composition", + "period": 2023, + "metadata": { + "contract_target_id": "ons.household_composition.unrelated_adult_households" + } + }, + { + "name": "ons.household_composition.couple_no_children_households", + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.families_households_table7", + "groupby_dimension": "ons.household_type", + "dimension_values": { + "household_type": "couple_no_children_households" + }, + "geography_level": "country" + }, + "entity": "household", + "measure": "ons/couple_no_children_households", + "family": "ons_household_composition", + "period": 2023, + "metadata": { + "contract_target_id": "ons.household_composition.couple_no_children_households" + } + }, + { + "name": "ons.household_composition.couple_under_3_children_households", + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.families_households_table7", + "groupby_dimension": "ons.household_type", + "dimension_values": { + "household_type": "couple_under_3_children_households" + }, + "geography_level": "country" + }, + "entity": "household", + "measure": "ons/couple_under_3_children_households", + "family": "ons_household_composition", + "period": 2023, + "metadata": { + "contract_target_id": "ons.household_composition.couple_under_3_children_households" + } + }, + { + "name": "ons.household_composition.couple_3_plus_children_households", + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.families_households_table7", + "groupby_dimension": "ons.household_type", + "dimension_values": { + "household_type": "couple_3_plus_children_households" + }, + "geography_level": "country" + }, + "entity": "household", + "measure": "ons/couple_3_plus_children_households", + "family": "ons_household_composition", + "period": 2023, + "metadata": { + "contract_target_id": "ons.household_composition.couple_3_plus_children_households" + } + }, + { + "name": "ons.household_composition.couple_non_dependent_children_only_households", + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.families_households_table7", + "groupby_dimension": "ons.household_type", + "dimension_values": { + "household_type": "couple_non_dependent_children_only_households" + }, + "geography_level": "country" + }, + "entity": "household", + "measure": "ons/couple_non_dependent_children_only_households", + "family": "ons_household_composition", + "period": 2023, + "metadata": { + "contract_target_id": "ons.household_composition.couple_non_dependent_children_only_households" + } + }, + { + "name": "ons.household_composition.lone_parent_dependent_children_households", + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.families_households_table7", + "groupby_dimension": "ons.household_type", + "dimension_values": { + "household_type": "lone_parent_dependent_children_households" + }, + "geography_level": "country" + }, + "entity": "household", + "measure": "ons/lone_parent_dependent_children_households", + "family": "ons_household_composition", + "period": 2023, + "metadata": { + "contract_target_id": "ons.household_composition.lone_parent_dependent_children_households" + } + }, + { + "name": "ons.household_composition.lone_parent_non_dependent_children_households", + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.families_households_table7", + "groupby_dimension": "ons.household_type", + "dimension_values": { + "household_type": "lone_parent_non_dependent_children_households" + }, + "geography_level": "country" + }, + "entity": "household", + "measure": "ons/lone_parent_non_dependent_children_households", + "family": "ons_household_composition", + "period": 2023, + "metadata": { + "contract_target_id": "ons.household_composition.lone_parent_non_dependent_children_households" + } + }, + { + "name": "ons.household_composition.multi_family_households", + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.families_households_table7", + "groupby_dimension": "ons.household_type", + "dimension_values": { + "household_type": "multi_family_households" + }, + "geography_level": "country" + }, + "entity": "household", + "measure": "ons/multi_family_households", + "family": "ons_household_composition", + "period": 2023, + "metadata": { + "contract_target_id": "ons.household_composition.multi_family_households" + } + }, + { + "name": "ons.savings_interest_income", + "ledger_selector": { + "source_name": "ons", + "source_concept": "ons.ukea_haxv", + "geography_level": "country" + }, + "entity": "person", + "measure": "ons/savings_interest_income", + "family": "ons_national_accounts", + "period": 2023, + "metadata": { + "contract_target_id": "ons.savings_interest_income" + } + }, + { + "name": "ons.public_sector_employment", + "ledger_selector": { + "source_name": "ons", + "source_measure_id": "total_public_sector", + "geography_level": "country" + }, + "entity": "person", + "measure": "ons/public_sector_employment", + "family": "ons_employment", + "period": 2023, + "metadata": { + "contract_target_id": "ons.public_sector_employment" + } + } + ] +} diff --git a/packages/microcosm-build/tests/test_country_spec.py b/packages/microcosm-build/tests/test_country_spec.py index d92d4d5c8..81ebbee39 100644 --- a/packages/microcosm-build/tests/test_country_spec.py +++ b/packages/microcosm-build/tests/test_country_spec.py @@ -300,8 +300,8 @@ def test_us_package_loads(self) -> None: assert spec.sources is not None assert spec.support_spine is not None # US target references live in fiscal_target_references.json (an - # untyped resource its runtime interprets); the typed - # target_references.json convention starts with Belgium. + # untyped resource its runtime interprets); Belgium and the UK use the + # typed target_references.json convention. assert spec.target_references == () def test_uk_package_loads(self) -> None: @@ -327,6 +327,7 @@ def test_uk_package_loads(self) -> None: "was_wealth_support_bounds.json", "uk_local_target_census.json", "uk_national_targets.json", + "target_references.json", ) diff --git a/packages/microcosm-build/tests/test_uk_target_references.py b/packages/microcosm-build/tests/test_uk_target_references.py new file mode 100644 index 000000000..dbf384359 --- /dev/null +++ b/packages/microcosm-build/tests/test_uk_target_references.py @@ -0,0 +1,237 @@ +"""Guarantees for the UK active-subset Ledger target references. + +``uk/target_references.json`` is the typed activation surface derived from the +value-free UK national contract. Observed values remain in Ledger facts; this +resource only declares which 2023 country-level facts Microcosm activates. +""" + +from __future__ import annotations + +import json +from importlib import resources as importlib_resources + +from microcosm.build.country_spec import load_country_spec +from microcosm.build.ledger_targets import compile_ledger_target_references + +ACTIVE_REFERENCE_COUNT = 13 + + +def _load_uk_resource(name: str) -> dict: + return json.loads( + importlib_resources.files("microcosm.build.uk").joinpath(name).read_text() + ) + + +def _contract_targets_by_id() -> dict[str, dict]: + contract = _load_uk_resource("uk_national_targets.json") + return {target["target_id"]: target for target in contract["targets"]} + + +def _expected_reference_entity(target: dict) -> str: + binding = target["bindings"]["policyengine"] + return binding.get("from_entity") or binding.get("map_to") or "household" + + +def test_uk_target_references_load_as_typed_non_empty_resource() -> None: + spec = load_country_spec("uk") + + assert len(spec.target_references) == ACTIVE_REFERENCE_COUNT + assert {reference.name for reference in spec.target_references} + + +def test_uk_target_references_follow_contract_derivation_rules() -> None: + resource = _load_uk_resource("target_references.json") + targets_by_id = _contract_targets_by_id() + names = [reference["name"] for reference in resource["target_references"]] + + assert resource["country"] == "uk" + assert resource["allowed_value_operations"] == ["identity"] + assert len(names) == len(set(names)) + + for reference in resource["target_references"]: + contract_target_id = reference["metadata"]["contract_target_id"] + target = targets_by_id[contract_target_id] + binding = target["bindings"]["policyengine"] + + assert reference["name"] == contract_target_id + assert reference["ledger_selector"] == { + **target["ledger_selector"], + "geography_level": "country", + } + assert reference["entity"] == _expected_reference_entity(target) + assert reference["measure"] == binding["metric_name"] + assert reference["family"] == target["family"] + assert reference["period"] == 2023 + assert reference["metadata"] == {"contract_target_id": contract_target_id} + + +def test_uk_target_references_compile_from_real_staged_feed_rows() -> None: + spec = load_country_spec("uk") + references = [ + reference + for reference in spec.target_references + if reference.name + in {"isc.private_school_students", "ons.savings_interest_income"} + ] + + registry = compile_ledger_target_references( + _real_uk_consumer_fact_rows(), + references, + country="uk", + ) + + targets = {target.name: target for target in registry.specs} + assert set(targets) == { + "isc.private_school_students", + "ons.savings_interest_income", + } + + private_school_students = targets["isc.private_school_students"] + assert private_school_students.value == 554_243 + assert private_school_students.period == 2023 + assert private_school_students.entity == "person" + assert private_school_students.measure == "obr/private_school_students" + assert private_school_students.family == "isc" + assert ( + private_school_students.metadata["contract_target_id"] + == "isc.private_school_students" + ) + assert ( + private_school_students.metadata["ledger_aggregate_fact_key"] + == "ledger.aggregate_fact.v2:a36696207826083b6dd7e878" + ) + + savings_interest = targets["ons.savings_interest_income"] + assert savings_interest.value == 86_040_000_000 + assert savings_interest.period == 2023 + assert savings_interest.entity == "person" + assert savings_interest.measure == "ons/savings_interest_income" + assert savings_interest.family == "ons_national_accounts" + assert ( + savings_interest.metadata["contract_target_id"] + == "ons.savings_interest_income" + ) + assert ( + savings_interest.metadata["ledger_aggregate_fact_key"] + == "ledger.aggregate_fact.v2:2d8306be080946696b35e1ee" + ) + + +def _real_uk_consumer_fact_rows() -> list[dict]: + """Public rows copied from .codex-work/consumer_facts_uk.jsonl.""" + + return [ + { + "aggregate_fact_key": "ledger.aggregate_fact.v2:a36696207826083b6dd7e878", + "aggregation": {"method": "sum"}, + "assertion": "observation", + "concept_alignment": { + "authority": "isc", + "canonical_concept": "isc.pupils_at_member_schools", + "relation": "source_label", + "source_concept": "isc.pupils_at_member_schools", + }, + "dimension_set_key": "ledger.dimension_set.v2:798fe9e6b99defdb40a97be3", + "dimensions": {"school_membership": "isc"}, + "entity": {"name": "person", "role": "private_school_pupil"}, + "geography": { + "id": "K02000001", + "level": "country", + "vintage": "current", + }, + "layout": { + "groupby_dimension": "isc.census_line", + "groupby_value_id": "pupils_at_isc_schools", + "measure_id": "pupils", + "record_set_id": "isc.census_2023.pupils", + }, + "legacy_fact_key": "ledger.fact.v1:6862b35fc66e993fd1b3a496", + "lineage": { + "source_record_id": ( + "isc.census_2023.pupils.pupils_at_isc_schools.pupils" + ) + }, + "observed_measure": { + "source_concept": "isc.pupils_at_member_schools", + "source_measure_id": "pupils", + "source_name": "isc", + "source_table": "ISC annual Census 2023", + "unit": "count", + }, + "period": {"type": "month", "value": "2023-01"}, + "semantic_fact_key": "ledger.semantic_fact.v2:dcdb6fab7a97e0d16f5332a0", + "source": { + "source_file": "isc_census_2023_final.pdf", + "source_name": "isc", + "source_table": "ISC annual Census 2023", + "url": "https://www.isc.co.uk/media/9316/isc_census_2023_final.pdf", + "vintage": "census_2023", + }, + "universe_constraint_set_key": ( + "ledger.universe_constraint_set.v2:6128dc3fab81d86b2f1e7d92" + ), + "universe_constraints": {"domain": "independent_school_education"}, + "value": 554_243, + "value_type": "integer", + }, + { + "aggregate_fact_key": "ledger.aggregate_fact.v2:2d8306be080946696b35e1ee", + "aggregation": {"method": "sum"}, + "assertion": "observation", + "concept_alignment": { + "authority": "ons", + "canonical_concept": "ons.household_interest_resources", + "relation": "source_label", + "source_concept": "ons.ukea_haxv", + }, + "dimension_set_key": "ledger.dimension_set.v2:44136fa355b3678a1146ad16", + "dimensions": {}, + "entity": {"name": "household", "role": "resident_household"}, + "geography": { + "id": "K02000001", + "level": "country", + "vintage": "current", + }, + "layout": { + "groupby_dimension": "ons.ukea_series", + "groupby_value_id": "haxv", + "measure_id": "amount", + "record_set_id": "ons.ukea_haxv.savings_interest.cy2023", + }, + "legacy_fact_key": "ledger.fact.v1:26472d1cd1730a29a966ad7c", + "lineage": { + "source_record_id": "ons.ukea_haxv.savings_interest.cy2023.haxv.amount" + }, + "observed_measure": { + "source_concept": "ons.ukea_haxv", + "source_measure_id": "amount", + "source_name": "ons", + "source_table": ( + "UKEA time series HAXV: Households (S.14) interest (D.41) " + "resources, current price GBP million NSA" + ), + "unit": "gbp", + }, + "period": {"type": "calendar_year", "value": 2023}, + "semantic_fact_key": "ledger.semantic_fact.v2:9ac263134990690ff4d4aeca", + "source": { + "source_file": "haxv.csv", + "source_name": "ons", + "source_table": ( + "UKEA time series HAXV: Households (S.14) interest (D.41) " + "resources, current price GBP million NSA" + ), + "url": ( + "https://www.ons.gov.uk/generator?format=csv&uri=/economy/" + "grossdomesticproductgdp/timeseries/haxv/ukea" + ), + "vintage": "ukea_2026_06_30", + }, + "universe_constraint_set_key": ( + "ledger.universe_constraint_set.v2:fa6e32cc24b49ed112373325" + ), + "universe_constraints": {"domain": "national_accounts"}, + "value": 86_040_000_000, + "value_type": "integer", + }, + ] From 0ee5cbe35460223c34badcdde5688adae1eddaa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20Juaristi?= <127882282+juaristi22@users.noreply.github.com> Date: Tue, 18 Aug 2026 17:57:58 +0200 Subject: [PATCH 06/10] Add changelog fragments for the UK contract adoption and active subset Co-Authored-By: Claude Fable 5 --- changelog.d/622-uk-national-contract.added.md | 4 ++++ changelog.d/622-uk-target-references.added.md | 3 +++ 2 files changed, 7 insertions(+) create mode 100644 changelog.d/622-uk-national-contract.added.md create mode 100644 changelog.d/622-uk-target-references.added.md diff --git a/changelog.d/622-uk-national-contract.added.md b/changelog.d/622-uk-national-contract.added.md new file mode 100644 index 000000000..3b4e53356 --- /dev/null +++ b/changelog.d/622-uk-national-contract.added.md @@ -0,0 +1,4 @@ +Add the hardened UK national calibration contract resource with signed +registry-parity accounting, explicit closure for carried unmapped +declarations, and review-pinned selector/binding invariants for the #622 UK +target migration. diff --git a/changelog.d/622-uk-target-references.added.md b/changelog.d/622-uk-target-references.added.md new file mode 100644 index 000000000..fa07b2bb5 --- /dev/null +++ b/changelog.d/622-uk-target-references.added.md @@ -0,0 +1,3 @@ +Add typed UK 2023 active-subset Ledger target references plus the shared +selector vocabulary needed to resolve Chronicle-derived selectors by +dimensions, dimension values, groupby dimension, and record-set id. From 09e31f00f95ebe8b4b578ff8ce7274d8ac8cef43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20Juaristi?= <127882282+juaristi22@users.noreply.github.com> Date: Wed, 19 Aug 2026 10:47:53 +0200 Subject: [PATCH 07/10] Make the prepared-column measure contract explicit and prove it end to end MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adversarial-review response: every active reference's metadata now carries measure_kind: prepared_column and the file description states the contract — the measure names the slash-named column the #622 UK materializer must prepare from the contract binding payload (US prepared-indicator-column doctrine; a raw value_variable measure would mis-constrain every filtered count). New test compiles all 13 references from committed real feed rows and builds the constraint matrix against a frame with one hand-prepared column per measure: zero skipped targets, exact row aggregates, fact values on the right-hand side. Derivation test now also asserts each active reference's binding carries value_variable. Co-Authored-By: Claude Fable 5 --- .../microcosm/build/uk/target_references.json | 41 ++++++--- .../uk_target_reference_feed_rows.jsonl | 13 +++ .../tests/test_uk_target_references.py | 90 ++++++++++++++++++- 3 files changed, 129 insertions(+), 15 deletions(-) create mode 100644 packages/microcosm-build/tests/fixtures/uk_target_reference_feed_rows.jsonl diff --git a/packages/microcosm-build/src/microcosm/build/uk/target_references.json b/packages/microcosm-build/src/microcosm/build/uk/target_references.json index 568045c85..21741acdb 100644 --- a/packages/microcosm-build/src/microcosm/build/uk/target_references.json +++ b/packages/microcosm-build/src/microcosm/build/uk/target_references.json @@ -1,6 +1,6 @@ { "country": "uk", - "description": "UK active-subset Ledger target references for the national 2023 spine. Rows are generated from uk_national_targets.json: name is the contract target_id; ledger_selector is the contract selector plus geography_level country for the first national activation; entity is from_entity, then map_to, then household; measure is bindings.policyengine.metric_name; family is the contract family; period is 2023; metadata.contract_target_id points back to the contract row. Observed values stay in Ledger facts and resolve by identity only. Deferred classes are recorded in .codex-work/membership_report.json: no fact at or before 2023, multi-fact sum resolution pending, source-projection policy pending, country-level geography ambiguity, or missing/non-finite fact values.", + "description": "UK active-subset Ledger target references for the national 2023 spine. Rows are generated from uk_national_targets.json: name is the contract target_id; ledger_selector is the contract selector plus geography_level country for the first national activation; entity is from_entity, then map_to, then household; measure is bindings.policyengine.metric_name; family is the contract family; period is 2023; metadata.contract_target_id points back to the contract row. Observed values stay in Ledger facts and resolve by identity only. Deferred classes are recorded in .codex-work/membership_report.json: no fact at or before 2023, multi-fact sum resolution pending, source-projection policy pending, country-level geography ambiguity, or missing/non-finite fact values. Measures name prepared columns, not raw model variables: each reference's measure is the slash-named column the microcosm#622 UK materializer must prepare on the reference's entity table from the contract binding payload (value_variable plus filters/conditions) referenced by metadata.contract_target_id, following the US prepared-indicator-column doctrine (target_spec_from_ledger_reference: count-like facts are sums of prepared indicator columns; the JCT materializer names household columns after their targets). metadata.measure_kind records this on every row.", "allowed_value_operations": [ "identity" ], @@ -17,7 +17,8 @@ "family": "isc", "period": 2023, "metadata": { - "contract_target_id": "isc.private_school_students" + "contract_target_id": "isc.private_school_students", + "measure_kind": "prepared_column" } }, { @@ -36,7 +37,8 @@ "family": "ons_household_composition", "period": 2023, "metadata": { - "contract_target_id": "ons.household_composition.lone_households_under_65" + "contract_target_id": "ons.household_composition.lone_households_under_65", + "measure_kind": "prepared_column" } }, { @@ -55,7 +57,8 @@ "family": "ons_household_composition", "period": 2023, "metadata": { - "contract_target_id": "ons.household_composition.lone_households_over_65" + "contract_target_id": "ons.household_composition.lone_households_over_65", + "measure_kind": "prepared_column" } }, { @@ -74,7 +77,8 @@ "family": "ons_household_composition", "period": 2023, "metadata": { - "contract_target_id": "ons.household_composition.unrelated_adult_households" + "contract_target_id": "ons.household_composition.unrelated_adult_households", + "measure_kind": "prepared_column" } }, { @@ -93,7 +97,8 @@ "family": "ons_household_composition", "period": 2023, "metadata": { - "contract_target_id": "ons.household_composition.couple_no_children_households" + "contract_target_id": "ons.household_composition.couple_no_children_households", + "measure_kind": "prepared_column" } }, { @@ -112,7 +117,8 @@ "family": "ons_household_composition", "period": 2023, "metadata": { - "contract_target_id": "ons.household_composition.couple_under_3_children_households" + "contract_target_id": "ons.household_composition.couple_under_3_children_households", + "measure_kind": "prepared_column" } }, { @@ -131,7 +137,8 @@ "family": "ons_household_composition", "period": 2023, "metadata": { - "contract_target_id": "ons.household_composition.couple_3_plus_children_households" + "contract_target_id": "ons.household_composition.couple_3_plus_children_households", + "measure_kind": "prepared_column" } }, { @@ -150,7 +157,8 @@ "family": "ons_household_composition", "period": 2023, "metadata": { - "contract_target_id": "ons.household_composition.couple_non_dependent_children_only_households" + "contract_target_id": "ons.household_composition.couple_non_dependent_children_only_households", + "measure_kind": "prepared_column" } }, { @@ -169,7 +177,8 @@ "family": "ons_household_composition", "period": 2023, "metadata": { - "contract_target_id": "ons.household_composition.lone_parent_dependent_children_households" + "contract_target_id": "ons.household_composition.lone_parent_dependent_children_households", + "measure_kind": "prepared_column" } }, { @@ -188,7 +197,8 @@ "family": "ons_household_composition", "period": 2023, "metadata": { - "contract_target_id": "ons.household_composition.lone_parent_non_dependent_children_households" + "contract_target_id": "ons.household_composition.lone_parent_non_dependent_children_households", + "measure_kind": "prepared_column" } }, { @@ -207,7 +217,8 @@ "family": "ons_household_composition", "period": 2023, "metadata": { - "contract_target_id": "ons.household_composition.multi_family_households" + "contract_target_id": "ons.household_composition.multi_family_households", + "measure_kind": "prepared_column" } }, { @@ -222,7 +233,8 @@ "family": "ons_national_accounts", "period": 2023, "metadata": { - "contract_target_id": "ons.savings_interest_income" + "contract_target_id": "ons.savings_interest_income", + "measure_kind": "prepared_column" } }, { @@ -237,7 +249,8 @@ "family": "ons_employment", "period": 2023, "metadata": { - "contract_target_id": "ons.public_sector_employment" + "contract_target_id": "ons.public_sector_employment", + "measure_kind": "prepared_column" } } ] diff --git a/packages/microcosm-build/tests/fixtures/uk_target_reference_feed_rows.jsonl b/packages/microcosm-build/tests/fixtures/uk_target_reference_feed_rows.jsonl new file mode 100644 index 000000000..9ee97bec4 --- /dev/null +++ b/packages/microcosm-build/tests/fixtures/uk_target_reference_feed_rows.jsonl @@ -0,0 +1,13 @@ +{"aggregate_fact_key": "ledger.aggregate_fact.v2:a36696207826083b6dd7e878", "aggregation": {"method": "sum"}, "assertion": "observation", "concept_alignment": {"authority": "isc", "canonical_concept": "isc.pupils_at_member_schools", "concept_alignment_key": "ledger.concept_alignment.v2:98bb32323a3c2baec9cf6536", "evidence_notes": "ISC annual Census 2023 report, executive summary: 554,243 pupils at 1,395 ISC member schools (survey carried out in January 2023, all UK-member schools responding).", "evidence_url": "https://www.isc.co.uk/research/annual-census/isc-annual-census-2023/", "relation": "source_label", "source_concept": "isc.pupils_at_member_schools"}, "dimension_set_key": "ledger.dimension_set.v2:798fe9e6b99defdb40a97be3", "dimensions": {"school_membership": "isc"}, "entity": {"name": "person", "role": "private_school_pupil"}, "geography": {"id": "K02000001", "level": "country", "vintage": "current"}, "label": "United Kingdom 2023-01 month count isc pupils at member schools for person (school membership=isc) [isc ISC annual Census 2023 isc_census_2023_final.pdf census_2023]", "layout": {"groupby_dimension": "isc.census_line", "groupby_ordinal": 0, "groupby_value_id": "pupils_at_isc_schools", "groupby_value_label": "Pupils at ISC member schools, January 2023 census", "measure_id": "pupils", "measure_label": "Pupils at ISC member schools", "measure_ordinal": 0, "record_set_id": "isc.census_2023.pupils", "record_set_spec_hash": "43d489f56ecef6c1f4f07827", "record_set_spec_id": "isc.census_2023.pupils.v1", "source_column_id": "numeric_value", "source_row_id": "pupils_at_isc_schools", "table_record_kind": "total"}, "legacy_fact_key": "ledger.fact.v1:6862b35fc66e993fd1b3a496", "lineage": {"source_cell_keys": ["ledger.source_cell.v1:8a85b6a60f996e8543bb2c70", "ledger.source_cell.v1:6dd528b0c45a1e8bf858158e", "ledger.source_cell.v1:d320f7b228df1df500407034", "ledger.source_cell.v1:5136187fe3a031fc10a0ca62"], "source_record_id": "isc.census_2023.pupils.pupils_at_isc_schools.pupils", "source_row_keys": []}, "observed_measure": {"source_concept": "isc.pupils_at_member_schools", "source_measure_id": "pupils", "source_name": "isc", "source_table": "ISC annual Census 2023", "unit": "count"}, "observed_measure_key": "ledger.observed_measure.v2:66d9adbd08e45f85b730163d", "period": {"type": "month", "value": "2023-01"}, "provenance_class": "census", "schema_version": "ledger.consumer_fact.v1", "semantic_fact_key": "ledger.semantic_fact.v2:dcdb6fab7a97e0d16f5332a0", "source": {"extracted_at": "2026-08-07", "extraction_method": "CellSelectorSpec and SourceRecordSpec resolved from cells", "method_notes": "Each fact carries source_record_id, source_cell_keys, and source_row_keys when available.", "raw_r2_bucket": "ledger-raw", "raw_r2_key": "raw/isc/isc-annual-census-2023/2023/67ae15ec91c626522b964fabe7c1624de9b83fcae356ebf2a240bf8c9adf35d8/isc_census_2023_final.pdf", "raw_r2_uri": "r2://ledger-raw/raw/isc/isc-annual-census-2023/2023/67ae15ec91c626522b964fabe7c1624de9b83fcae356ebf2a240bf8c9adf35d8/isc_census_2023_final.pdf", "source_file": "isc_census_2023_final.pdf", "source_name": "isc", "source_sha256": "67ae15ec91c626522b964fabe7c1624de9b83fcae356ebf2a240bf8c9adf35d8", "source_size_bytes": 6061790, "source_table": "ISC annual Census 2023", "url": "https://www.isc.co.uk/media/9316/isc_census_2023_final.pdf", "vintage": "census_2023"}, "source_release_key": "ledger.source_release.v2:a60ce5f6bbc36d63507667d9", "source_series_key": "ledger.source_series.v2:8bc0947d65be226dd5348907", "universe_constraint_set_key": "ledger.universe_constraint_set.v2:6128dc3fab81d86b2f1e7d92", "universe_constraints": {"constraints": [{"operator": "==", "role": "filter", "value": "isc", "variable": "school_membership"}], "domain": "independent_school_education"}, "value": 554243, "value_type": "integer"} +{"aggregate_fact_key": "ledger.aggregate_fact.v2:0b3bba939da29c3b925d98a8", "aggregation": {"method": "sum"}, "assertion": "observation", "concept_alignment": {"authority": "ons", "canonical_concept": "ons.households_by_type", "concept_alignment_key": "ledger.concept_alignment.v2:cf85783836063df6a5d4ade3", "evidence_notes": "Families and households in the UK, 2025 edition, Table 7 households by type, 2023 estimate, thousands.", "evidence_url": "https://www.ons.gov.uk/peoplepopulationandcommunity/birthsdeathsandmarriages/families/datasets/familiesandhouseholdsfamiliesandhouseholds", "relation": "source_label", "source_concept": "ons.families_households_table7"}, "dimension_set_key": "ledger.dimension_set.v2:5ea829aca1b48c2ce225a06e", "dimensions": {"household_type": "lone_households_under_65"}, "entity": {"name": "household", "role": "resident_household"}, "geography": {"id": "K02000001", "level": "country", "vintage": "current"}, "label": "United Kingdom 2023 calendar year count ons households by type for household (household type=lone households under 65) [ons Families and households in the UK 2025, Table 7: households by type familiesandhouseholdsuk2025.xlsx families_households_2025]", "layout": {"groupby_dimension": "ons.household_type", "groupby_ordinal": 0, "groupby_value_id": "lone_households_under_65", "groupby_value_label": "Under 65", "measure_id": "households", "measure_label": "Households, 2023 estimate", "measure_ordinal": 0, "record_set_id": "ons.families_households_2025.table7.cy2023", "record_set_spec_hash": "0ea9705065c1ac17dfce8be4", "record_set_spec_id": "ons.families_households_2025.table7.cy2023.v1", "source_column_id": "households", "source_row_id": "lone_households_under_65", "table_record_kind": "detail"}, "legacy_fact_key": "ledger.fact.v1:c2b4362848754d3e02c7a08a", "lineage": {"source_cell_keys": ["ledger.source_cell.v1:837e34887b59a7fc491f97f8", "ledger.source_cell.v1:2531e3e8f7340928e989b0ef"], "source_record_id": "ons.families_households_2025.table7.cy2023.lone_households_under_65.households", "source_row_keys": []}, "observed_measure": {"source_concept": "ons.families_households_table7", "source_measure_id": "households", "source_name": "ons", "source_table": "Families and households in the UK 2025, Table 7: households by type", "unit": "count"}, "observed_measure_key": "ledger.observed_measure.v2:f5e97dfafe656d78d5ad97fc", "period": {"type": "calendar_year", "value": 2023}, "provenance_class": "survey_aggregate", "schema_version": "ledger.consumer_fact.v1", "semantic_fact_key": "ledger.semantic_fact.v2:6efcfd7990cdaa436ac411d3", "source": {"extracted_at": "2026-08-06", "extraction_method": "CellSelectorSpec and SourceRecordSpec resolved from cells", "method_notes": "Each fact carries source_record_id, source_cell_keys, and source_row_keys when available.", "raw_r2_bucket": "ledger-raw", "raw_r2_key": "raw/ons/ons-families-households-2025/2025/a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91/familiesandhouseholdsuk2025.xlsx", "raw_r2_uri": "r2://ledger-raw/raw/ons/ons-families-households-2025/2025/a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91/familiesandhouseholdsuk2025.xlsx", "source_file": "familiesandhouseholdsuk2025.xlsx", "source_name": "ons", "source_sha256": "a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91", "source_size_bytes": 209085, "source_table": "Families and households in the UK 2025, Table 7: households by type", "url": "https://www.ons.gov.uk/file?uri=/peoplepopulationandcommunity/birthsdeathsandmarriages/families/datasets/familiesandhouseholdsfamiliesandhouseholds/current/familiesandhouseholdsuk2025.xlsx", "vintage": "families_households_2025"}, "source_release_key": "ledger.source_release.v2:30b0ffd8d7245b0d6684989e", "source_series_key": "ledger.source_series.v2:9faf1c83fb31f4a881373e3c", "survey_instrument": "Labour Force Survey", "universe_constraint_set_key": "ledger.universe_constraint_set.v2:294e9acfef7d58dfd3d0f201", "universe_constraints": {"constraints": [{"operator": "==", "role": "filter", "value": "lone_households_under_65", "variable": "household_type"}], "domain": "household_composition"}, "value": 4166000, "value_type": "integer"} +{"aggregate_fact_key": "ledger.aggregate_fact.v2:1ddf8c636c81c2f6b5036612", "aggregation": {"method": "sum"}, "assertion": "observation", "concept_alignment": {"authority": "ons", "canonical_concept": "ons.households_by_type", "concept_alignment_key": "ledger.concept_alignment.v2:cf85783836063df6a5d4ade3", "evidence_notes": "Families and households in the UK, 2025 edition, Table 7 households by type, 2023 estimate, thousands.", "evidence_url": "https://www.ons.gov.uk/peoplepopulationandcommunity/birthsdeathsandmarriages/families/datasets/familiesandhouseholdsfamiliesandhouseholds", "relation": "source_label", "source_concept": "ons.families_households_table7"}, "dimension_set_key": "ledger.dimension_set.v2:95a64ffacc62ab4a618e2c2d", "dimensions": {"household_type": "lone_households_over_65"}, "entity": {"name": "household", "role": "resident_household"}, "geography": {"id": "K02000001", "level": "country", "vintage": "current"}, "label": "United Kingdom 2023 calendar year count ons households by type for household (household type=lone households over 65) [ons Families and households in the UK 2025, Table 7: households by type familiesandhouseholdsuk2025.xlsx families_households_2025]", "layout": {"groupby_dimension": "ons.household_type", "groupby_ordinal": 1, "groupby_value_id": "lone_households_over_65", "groupby_value_label": "65 or over", "measure_id": "households", "measure_label": "Households, 2023 estimate", "measure_ordinal": 0, "record_set_id": "ons.families_households_2025.table7.cy2023", "record_set_spec_hash": "0ea9705065c1ac17dfce8be4", "record_set_spec_id": "ons.families_households_2025.table7.cy2023.v1", "source_column_id": "households", "source_row_id": "lone_households_over_65", "table_record_kind": "detail"}, "legacy_fact_key": "ledger.fact.v1:0eaabf6d0a7df5f5c44fc3b1", "lineage": {"source_cell_keys": ["ledger.source_cell.v1:eabeb69fafb8cb9869737539", "ledger.source_cell.v1:2531e3e8f7340928e989b0ef"], "source_record_id": "ons.families_households_2025.table7.cy2023.lone_households_over_65.households", "source_row_keys": []}, "observed_measure": {"source_concept": "ons.families_households_table7", "source_measure_id": "households", "source_name": "ons", "source_table": "Families and households in the UK 2025, Table 7: households by type", "unit": "count"}, "observed_measure_key": "ledger.observed_measure.v2:f5e97dfafe656d78d5ad97fc", "period": {"type": "calendar_year", "value": 2023}, "provenance_class": "survey_aggregate", "schema_version": "ledger.consumer_fact.v1", "semantic_fact_key": "ledger.semantic_fact.v2:47eb4dc37591df9cbcc7b86c", "source": {"extracted_at": "2026-08-06", "extraction_method": "CellSelectorSpec and SourceRecordSpec resolved from cells", "method_notes": "Each fact carries source_record_id, source_cell_keys, and source_row_keys when available.", "raw_r2_bucket": "ledger-raw", "raw_r2_key": "raw/ons/ons-families-households-2025/2025/a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91/familiesandhouseholdsuk2025.xlsx", "raw_r2_uri": "r2://ledger-raw/raw/ons/ons-families-households-2025/2025/a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91/familiesandhouseholdsuk2025.xlsx", "source_file": "familiesandhouseholdsuk2025.xlsx", "source_name": "ons", "source_sha256": "a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91", "source_size_bytes": 209085, "source_table": "Families and households in the UK 2025, Table 7: households by type", "url": "https://www.ons.gov.uk/file?uri=/peoplepopulationandcommunity/birthsdeathsandmarriages/families/datasets/familiesandhouseholdsfamiliesandhouseholds/current/familiesandhouseholdsuk2025.xlsx", "vintage": "families_households_2025"}, "source_release_key": "ledger.source_release.v2:30b0ffd8d7245b0d6684989e", "source_series_key": "ledger.source_series.v2:9faf1c83fb31f4a881373e3c", "survey_instrument": "Labour Force Survey", "universe_constraint_set_key": "ledger.universe_constraint_set.v2:b102ca2d480c2589316600cd", "universe_constraints": {"constraints": [{"operator": "==", "role": "filter", "value": "lone_households_over_65", "variable": "household_type"}], "domain": "household_composition"}, "value": 4214000, "value_type": "integer"} +{"aggregate_fact_key": "ledger.aggregate_fact.v2:8ef6c9992eabbc2e9641c694", "aggregation": {"method": "sum"}, "assertion": "observation", "concept_alignment": {"authority": "ons", "canonical_concept": "ons.households_by_type", "concept_alignment_key": "ledger.concept_alignment.v2:cf85783836063df6a5d4ade3", "evidence_notes": "Families and households in the UK, 2025 edition, Table 7 households by type, 2023 estimate, thousands.", "evidence_url": "https://www.ons.gov.uk/peoplepopulationandcommunity/birthsdeathsandmarriages/families/datasets/familiesandhouseholdsfamiliesandhouseholds", "relation": "source_label", "source_concept": "ons.families_households_table7"}, "dimension_set_key": "ledger.dimension_set.v2:5774a97907813719358f314f", "dimensions": {"household_type": "unrelated_adult_households"}, "entity": {"name": "household", "role": "resident_household"}, "geography": {"id": "K02000001", "level": "country", "vintage": "current"}, "label": "United Kingdom 2023 calendar year count ons households by type for household (household type=unrelated adult households) [ons Families and households in the UK 2025, Table 7: households by type familiesandhouseholdsuk2025.xlsx families_households_2025]", "layout": {"groupby_dimension": "ons.household_type", "groupby_ordinal": 2, "groupby_value_id": "unrelated_adult_households", "groupby_value_label": "Two or more unrelated adults [note 10]", "measure_id": "households", "measure_label": "Households, 2023 estimate", "measure_ordinal": 0, "record_set_id": "ons.families_households_2025.table7.cy2023", "record_set_spec_hash": "0ea9705065c1ac17dfce8be4", "record_set_spec_id": "ons.families_households_2025.table7.cy2023.v1", "source_column_id": "households", "source_row_id": "unrelated_adult_households", "table_record_kind": "detail"}, "legacy_fact_key": "ledger.fact.v1:97ed998e24b9fae08017d83a", "lineage": {"source_cell_keys": ["ledger.source_cell.v1:8d5efd7a126aaf30f68fb31d", "ledger.source_cell.v1:2531e3e8f7340928e989b0ef"], "source_record_id": "ons.families_households_2025.table7.cy2023.unrelated_adult_households.households", "source_row_keys": []}, "observed_measure": {"source_concept": "ons.families_households_table7", "source_measure_id": "households", "source_name": "ons", "source_table": "Families and households in the UK 2025, Table 7: households by type", "unit": "count"}, "observed_measure_key": "ledger.observed_measure.v2:f5e97dfafe656d78d5ad97fc", "period": {"type": "calendar_year", "value": 2023}, "provenance_class": "survey_aggregate", "schema_version": "ledger.consumer_fact.v1", "semantic_fact_key": "ledger.semantic_fact.v2:fff64222efad35d84be6b76f", "source": {"extracted_at": "2026-08-06", "extraction_method": "CellSelectorSpec and SourceRecordSpec resolved from cells", "method_notes": "Each fact carries source_record_id, source_cell_keys, and source_row_keys when available.", "raw_r2_bucket": "ledger-raw", "raw_r2_key": "raw/ons/ons-families-households-2025/2025/a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91/familiesandhouseholdsuk2025.xlsx", "raw_r2_uri": "r2://ledger-raw/raw/ons/ons-families-households-2025/2025/a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91/familiesandhouseholdsuk2025.xlsx", "source_file": "familiesandhouseholdsuk2025.xlsx", "source_name": "ons", "source_sha256": "a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91", "source_size_bytes": 209085, "source_table": "Families and households in the UK 2025, Table 7: households by type", "url": "https://www.ons.gov.uk/file?uri=/peoplepopulationandcommunity/birthsdeathsandmarriages/families/datasets/familiesandhouseholdsfamiliesandhouseholds/current/familiesandhouseholdsuk2025.xlsx", "vintage": "families_households_2025"}, "source_release_key": "ledger.source_release.v2:30b0ffd8d7245b0d6684989e", "source_series_key": "ledger.source_series.v2:9faf1c83fb31f4a881373e3c", "survey_instrument": "Labour Force Survey", "universe_constraint_set_key": "ledger.universe_constraint_set.v2:966db6efafedee1aa2bf9622", "universe_constraints": {"constraints": [{"operator": "==", "role": "filter", "value": "unrelated_adult_households", "variable": "household_type"}], "domain": "household_composition"}, "value": 827000, "value_type": "integer"} +{"aggregate_fact_key": "ledger.aggregate_fact.v2:69edec6d08e8bb80e11cb682", "aggregation": {"method": "sum"}, "assertion": "observation", "concept_alignment": {"authority": "ons", "canonical_concept": "ons.households_by_type", "concept_alignment_key": "ledger.concept_alignment.v2:cf85783836063df6a5d4ade3", "evidence_notes": "Families and households in the UK, 2025 edition, Table 7 households by type, 2023 estimate, thousands.", "evidence_url": "https://www.ons.gov.uk/peoplepopulationandcommunity/birthsdeathsandmarriages/families/datasets/familiesandhouseholdsfamiliesandhouseholds", "relation": "source_label", "source_concept": "ons.families_households_table7"}, "dimension_set_key": "ledger.dimension_set.v2:53e6f9397dd4db4747ca9d08", "dimensions": {"household_type": "couple_no_children_households"}, "entity": {"name": "household", "role": "resident_household"}, "geography": {"id": "K02000001", "level": "country", "vintage": "current"}, "label": "United Kingdom 2023 calendar year count ons households by type for household (household type=couple no children households) [ons Families and households in the UK 2025, Table 7: households by type familiesandhouseholdsuk2025.xlsx families_households_2025]", "layout": {"groupby_dimension": "ons.household_type", "groupby_ordinal": 3, "groupby_value_id": "couple_no_children_households", "groupby_value_label": "No children [note 7]", "measure_id": "households", "measure_label": "Households, 2023 estimate", "measure_ordinal": 0, "record_set_id": "ons.families_households_2025.table7.cy2023", "record_set_spec_hash": "0ea9705065c1ac17dfce8be4", "record_set_spec_id": "ons.families_households_2025.table7.cy2023.v1", "source_column_id": "households", "source_row_id": "couple_no_children_households", "table_record_kind": "detail"}, "legacy_fact_key": "ledger.fact.v1:59f4d215776ade6f38f973a6", "lineage": {"source_cell_keys": ["ledger.source_cell.v1:e55f7b353e3e47e85b5351e2", "ledger.source_cell.v1:2531e3e8f7340928e989b0ef"], "source_record_id": "ons.families_households_2025.table7.cy2023.couple_no_children_households.households", "source_row_keys": []}, "observed_measure": {"source_concept": "ons.families_households_table7", "source_measure_id": "households", "source_name": "ons", "source_table": "Families and households in the UK 2025, Table 7: households by type", "unit": "count"}, "observed_measure_key": "ledger.observed_measure.v2:f5e97dfafe656d78d5ad97fc", "period": {"type": "calendar_year", "value": 2023}, "provenance_class": "survey_aggregate", "schema_version": "ledger.consumer_fact.v1", "semantic_fact_key": "ledger.semantic_fact.v2:916305bb92da344beede7402", "source": {"extracted_at": "2026-08-06", "extraction_method": "CellSelectorSpec and SourceRecordSpec resolved from cells", "method_notes": "Each fact carries source_record_id, source_cell_keys, and source_row_keys when available.", "raw_r2_bucket": "ledger-raw", "raw_r2_key": "raw/ons/ons-families-households-2025/2025/a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91/familiesandhouseholdsuk2025.xlsx", "raw_r2_uri": "r2://ledger-raw/raw/ons/ons-families-households-2025/2025/a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91/familiesandhouseholdsuk2025.xlsx", "source_file": "familiesandhouseholdsuk2025.xlsx", "source_name": "ons", "source_sha256": "a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91", "source_size_bytes": 209085, "source_table": "Families and households in the UK 2025, Table 7: households by type", "url": "https://www.ons.gov.uk/file?uri=/peoplepopulationandcommunity/birthsdeathsandmarriages/families/datasets/familiesandhouseholdsfamiliesandhouseholds/current/familiesandhouseholdsuk2025.xlsx", "vintage": "families_households_2025"}, "source_release_key": "ledger.source_release.v2:30b0ffd8d7245b0d6684989e", "source_series_key": "ledger.source_series.v2:9faf1c83fb31f4a881373e3c", "survey_instrument": "Labour Force Survey", "universe_constraint_set_key": "ledger.universe_constraint_set.v2:6b6e7e8ef3885da74f69530b", "universe_constraints": {"constraints": [{"operator": "==", "role": "filter", "value": "couple_no_children_households", "variable": "household_type"}], "domain": "household_composition"}, "value": 7956000, "value_type": "integer"} +{"aggregate_fact_key": "ledger.aggregate_fact.v2:1a5bcf85cdb2440d2e2bbee3", "aggregation": {"method": "sum"}, "assertion": "observation", "concept_alignment": {"authority": "ons", "canonical_concept": "ons.households_by_type", "concept_alignment_key": "ledger.concept_alignment.v2:cf85783836063df6a5d4ade3", "evidence_notes": "Families and households in the UK, 2025 edition, Table 7 households by type, 2023 estimate, thousands.", "evidence_url": "https://www.ons.gov.uk/peoplepopulationandcommunity/birthsdeathsandmarriages/families/datasets/familiesandhouseholdsfamiliesandhouseholds", "relation": "source_label", "source_concept": "ons.families_households_table7"}, "dimension_set_key": "ledger.dimension_set.v2:12b5c2a1d4a0867350fd061c", "dimensions": {"household_type": "couple_under_3_children_households"}, "entity": {"name": "household", "role": "resident_household"}, "geography": {"id": "K02000001", "level": "country", "vintage": "current"}, "label": "United Kingdom 2023 calendar year count ons households by type for household (household type=couple under 3 children households) [ons Families and households in the UK 2025, Table 7: households by type familiesandhouseholdsuk2025.xlsx families_households_2025]", "layout": {"groupby_dimension": "ons.household_type", "groupby_ordinal": 4, "groupby_value_id": "couple_under_3_children_households", "groupby_value_label": "1 to 2 dependent children [note 5]", "measure_id": "households", "measure_label": "Households, 2023 estimate", "measure_ordinal": 0, "record_set_id": "ons.families_households_2025.table7.cy2023", "record_set_spec_hash": "0ea9705065c1ac17dfce8be4", "record_set_spec_id": "ons.families_households_2025.table7.cy2023.v1", "source_column_id": "households", "source_row_id": "couple_under_3_children_households", "table_record_kind": "detail"}, "legacy_fact_key": "ledger.fact.v1:0ebdade3b55e7559849eb107", "lineage": {"source_cell_keys": ["ledger.source_cell.v1:d07ff2fd8a7e64097d20dbcc", "ledger.source_cell.v1:2531e3e8f7340928e989b0ef"], "source_record_id": "ons.families_households_2025.table7.cy2023.couple_under_3_children_households.households", "source_row_keys": []}, "observed_measure": {"source_concept": "ons.families_households_table7", "source_measure_id": "households", "source_name": "ons", "source_table": "Families and households in the UK 2025, Table 7: households by type", "unit": "count"}, "observed_measure_key": "ledger.observed_measure.v2:f5e97dfafe656d78d5ad97fc", "period": {"type": "calendar_year", "value": 2023}, "provenance_class": "survey_aggregate", "schema_version": "ledger.consumer_fact.v1", "semantic_fact_key": "ledger.semantic_fact.v2:c1a357a1e496bb6d37a6c7a9", "source": {"extracted_at": "2026-08-06", "extraction_method": "CellSelectorSpec and SourceRecordSpec resolved from cells", "method_notes": "Each fact carries source_record_id, source_cell_keys, and source_row_keys when available.", "raw_r2_bucket": "ledger-raw", "raw_r2_key": "raw/ons/ons-families-households-2025/2025/a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91/familiesandhouseholdsuk2025.xlsx", "raw_r2_uri": "r2://ledger-raw/raw/ons/ons-families-households-2025/2025/a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91/familiesandhouseholdsuk2025.xlsx", "source_file": "familiesandhouseholdsuk2025.xlsx", "source_name": "ons", "source_sha256": "a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91", "source_size_bytes": 209085, "source_table": "Families and households in the UK 2025, Table 7: households by type", "url": "https://www.ons.gov.uk/file?uri=/peoplepopulationandcommunity/birthsdeathsandmarriages/families/datasets/familiesandhouseholdsfamiliesandhouseholds/current/familiesandhouseholdsuk2025.xlsx", "vintage": "families_households_2025"}, "source_release_key": "ledger.source_release.v2:30b0ffd8d7245b0d6684989e", "source_series_key": "ledger.source_series.v2:9faf1c83fb31f4a881373e3c", "survey_instrument": "Labour Force Survey", "universe_constraint_set_key": "ledger.universe_constraint_set.v2:d4e1d564c76bf14c2660f69c", "universe_constraints": {"constraints": [{"operator": "==", "role": "filter", "value": "couple_under_3_children_households", "variable": "household_type"}], "domain": "household_composition"}, "value": 5210000, "value_type": "integer"} +{"aggregate_fact_key": "ledger.aggregate_fact.v2:f9c5f6507123ddea8230de9b", "aggregation": {"method": "sum"}, "assertion": "observation", "concept_alignment": {"authority": "ons", "canonical_concept": "ons.households_by_type", "concept_alignment_key": "ledger.concept_alignment.v2:cf85783836063df6a5d4ade3", "evidence_notes": "Families and households in the UK, 2025 edition, Table 7 households by type, 2023 estimate, thousands.", "evidence_url": "https://www.ons.gov.uk/peoplepopulationandcommunity/birthsdeathsandmarriages/families/datasets/familiesandhouseholdsfamiliesandhouseholds", "relation": "source_label", "source_concept": "ons.families_households_table7"}, "dimension_set_key": "ledger.dimension_set.v2:d7fd900bfb7f45f15b68473f", "dimensions": {"household_type": "couple_3_plus_children_households"}, "entity": {"name": "household", "role": "resident_household"}, "geography": {"id": "K02000001", "level": "country", "vintage": "current"}, "label": "United Kingdom 2023 calendar year count ons households by type for household (household type=couple 3 plus children households) [ons Families and households in the UK 2025, Table 7: households by type familiesandhouseholdsuk2025.xlsx families_households_2025]", "layout": {"groupby_dimension": "ons.household_type", "groupby_ordinal": 5, "groupby_value_id": "couple_3_plus_children_households", "groupby_value_label": "3 or more dependent children [note 5]", "measure_id": "households", "measure_label": "Households, 2023 estimate", "measure_ordinal": 0, "record_set_id": "ons.families_households_2025.table7.cy2023", "record_set_spec_hash": "0ea9705065c1ac17dfce8be4", "record_set_spec_id": "ons.families_households_2025.table7.cy2023.v1", "source_column_id": "households", "source_row_id": "couple_3_plus_children_households", "table_record_kind": "detail"}, "legacy_fact_key": "ledger.fact.v1:c3fb5e9030abcebf649711e6", "lineage": {"source_cell_keys": ["ledger.source_cell.v1:2d007d1d11f4156c26546aa6", "ledger.source_cell.v1:2531e3e8f7340928e989b0ef"], "source_record_id": "ons.families_households_2025.table7.cy2023.couple_3_plus_children_households.households", "source_row_keys": []}, "observed_measure": {"source_concept": "ons.families_households_table7", "source_measure_id": "households", "source_name": "ons", "source_table": "Families and households in the UK 2025, Table 7: households by type", "unit": "count"}, "observed_measure_key": "ledger.observed_measure.v2:f5e97dfafe656d78d5ad97fc", "period": {"type": "calendar_year", "value": 2023}, "provenance_class": "survey_aggregate", "schema_version": "ledger.consumer_fact.v1", "semantic_fact_key": "ledger.semantic_fact.v2:5bdc916cbf1d7f0b0ea5bcc7", "source": {"extracted_at": "2026-08-06", "extraction_method": "CellSelectorSpec and SourceRecordSpec resolved from cells", "method_notes": "Each fact carries source_record_id, source_cell_keys, and source_row_keys when available.", "raw_r2_bucket": "ledger-raw", "raw_r2_key": "raw/ons/ons-families-households-2025/2025/a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91/familiesandhouseholdsuk2025.xlsx", "raw_r2_uri": "r2://ledger-raw/raw/ons/ons-families-households-2025/2025/a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91/familiesandhouseholdsuk2025.xlsx", "source_file": "familiesandhouseholdsuk2025.xlsx", "source_name": "ons", "source_sha256": "a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91", "source_size_bytes": 209085, "source_table": "Families and households in the UK 2025, Table 7: households by type", "url": "https://www.ons.gov.uk/file?uri=/peoplepopulationandcommunity/birthsdeathsandmarriages/families/datasets/familiesandhouseholdsfamiliesandhouseholds/current/familiesandhouseholdsuk2025.xlsx", "vintage": "families_households_2025"}, "source_release_key": "ledger.source_release.v2:30b0ffd8d7245b0d6684989e", "source_series_key": "ledger.source_series.v2:9faf1c83fb31f4a881373e3c", "survey_instrument": "Labour Force Survey", "universe_constraint_set_key": "ledger.universe_constraint_set.v2:c4e4babbd1e59a47ffbb0a02", "universe_constraints": {"constraints": [{"operator": "==", "role": "filter", "value": "couple_3_plus_children_households", "variable": "household_type"}], "domain": "household_composition"}, "value": 907000, "value_type": "integer"} +{"aggregate_fact_key": "ledger.aggregate_fact.v2:b8c8ee8287142d33e8c4d258", "aggregation": {"method": "sum"}, "assertion": "observation", "concept_alignment": {"authority": "ons", "canonical_concept": "ons.households_by_type", "concept_alignment_key": "ledger.concept_alignment.v2:cf85783836063df6a5d4ade3", "evidence_notes": "Families and households in the UK, 2025 edition, Table 7 households by type, 2023 estimate, thousands.", "evidence_url": "https://www.ons.gov.uk/peoplepopulationandcommunity/birthsdeathsandmarriages/families/datasets/familiesandhouseholdsfamiliesandhouseholds", "relation": "source_label", "source_concept": "ons.families_households_table7"}, "dimension_set_key": "ledger.dimension_set.v2:7942e7c827a3a477da809695", "dimensions": {"household_type": "couple_non_dependent_children_only_households"}, "entity": {"name": "household", "role": "resident_household"}, "geography": {"id": "K02000001", "level": "country", "vintage": "current"}, "label": "United Kingdom 2023 calendar year count ons households by type for household (household type=couple non dependent children only households) [ons Families and households in the UK 2025, Table 7: households by type familiesandhouseholdsuk2025.xlsx families_households_2025]", "layout": {"groupby_dimension": "ons.household_type", "groupby_ordinal": 6, "groupby_value_id": "couple_non_dependent_children_only_households", "groupby_value_label": "Non-dependent children only [note 6]", "measure_id": "households", "measure_label": "Households, 2023 estimate", "measure_ordinal": 0, "record_set_id": "ons.families_households_2025.table7.cy2023", "record_set_spec_hash": "0ea9705065c1ac17dfce8be4", "record_set_spec_id": "ons.families_households_2025.table7.cy2023.v1", "source_column_id": "households", "source_row_id": "couple_non_dependent_children_only_households", "table_record_kind": "detail"}, "legacy_fact_key": "ledger.fact.v1:a07847d3e21058cf8f58fe90", "lineage": {"source_cell_keys": ["ledger.source_cell.v1:eebbbb8900482c3d7352b7e5", "ledger.source_cell.v1:2531e3e8f7340928e989b0ef"], "source_record_id": "ons.families_households_2025.table7.cy2023.couple_non_dependent_children_only_households.households", "source_row_keys": []}, "observed_measure": {"source_concept": "ons.families_households_table7", "source_measure_id": "households", "source_name": "ons", "source_table": "Families and households in the UK 2025, Table 7: households by type", "unit": "count"}, "observed_measure_key": "ledger.observed_measure.v2:f5e97dfafe656d78d5ad97fc", "period": {"type": "calendar_year", "value": 2023}, "provenance_class": "survey_aggregate", "schema_version": "ledger.consumer_fact.v1", "semantic_fact_key": "ledger.semantic_fact.v2:7ec88da6a8718f9ab9aa5415", "source": {"extracted_at": "2026-08-06", "extraction_method": "CellSelectorSpec and SourceRecordSpec resolved from cells", "method_notes": "Each fact carries source_record_id, source_cell_keys, and source_row_keys when available.", "raw_r2_bucket": "ledger-raw", "raw_r2_key": "raw/ons/ons-families-households-2025/2025/a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91/familiesandhouseholdsuk2025.xlsx", "raw_r2_uri": "r2://ledger-raw/raw/ons/ons-families-households-2025/2025/a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91/familiesandhouseholdsuk2025.xlsx", "source_file": "familiesandhouseholdsuk2025.xlsx", "source_name": "ons", "source_sha256": "a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91", "source_size_bytes": 209085, "source_table": "Families and households in the UK 2025, Table 7: households by type", "url": "https://www.ons.gov.uk/file?uri=/peoplepopulationandcommunity/birthsdeathsandmarriages/families/datasets/familiesandhouseholdsfamiliesandhouseholds/current/familiesandhouseholdsuk2025.xlsx", "vintage": "families_households_2025"}, "source_release_key": "ledger.source_release.v2:30b0ffd8d7245b0d6684989e", "source_series_key": "ledger.source_series.v2:9faf1c83fb31f4a881373e3c", "survey_instrument": "Labour Force Survey", "universe_constraint_set_key": "ledger.universe_constraint_set.v2:93df84662f9006f179b40205", "universe_constraints": {"constraints": [{"operator": "==", "role": "filter", "value": "couple_non_dependent_children_only_households", "variable": "household_type"}], "domain": "household_composition"}, "value": 1793000, "value_type": "integer"} +{"aggregate_fact_key": "ledger.aggregate_fact.v2:8de5968337dd81ca4f8535df", "aggregation": {"method": "sum"}, "assertion": "observation", "concept_alignment": {"authority": "ons", "canonical_concept": "ons.households_by_type", "concept_alignment_key": "ledger.concept_alignment.v2:cf85783836063df6a5d4ade3", "evidence_notes": "Families and households in the UK, 2025 edition, Table 7 households by type, 2023 estimate, thousands.", "evidence_url": "https://www.ons.gov.uk/peoplepopulationandcommunity/birthsdeathsandmarriages/families/datasets/familiesandhouseholdsfamiliesandhouseholds", "relation": "source_label", "source_concept": "ons.families_households_table7"}, "dimension_set_key": "ledger.dimension_set.v2:5e7a4436130bc8818b1d00c7", "dimensions": {"household_type": "lone_parent_dependent_children_households"}, "entity": {"name": "household", "role": "resident_household"}, "geography": {"id": "K02000001", "level": "country", "vintage": "current"}, "label": "United Kingdom 2023 calendar year count ons households by type for household (household type=lone parent dependent children households) [ons Families and households in the UK 2025, Table 7: households by type familiesandhouseholdsuk2025.xlsx families_households_2025]", "layout": {"groupby_dimension": "ons.household_type", "groupby_ordinal": 7, "groupby_value_id": "lone_parent_dependent_children_households", "groupby_value_label": "Dependent children [note 5]", "measure_id": "households", "measure_label": "Households, 2023 estimate", "measure_ordinal": 0, "record_set_id": "ons.families_households_2025.table7.cy2023", "record_set_spec_hash": "0ea9705065c1ac17dfce8be4", "record_set_spec_id": "ons.families_households_2025.table7.cy2023.v1", "source_column_id": "households", "source_row_id": "lone_parent_dependent_children_households", "table_record_kind": "detail"}, "legacy_fact_key": "ledger.fact.v1:f731755c1eb1257215325eb5", "lineage": {"source_cell_keys": ["ledger.source_cell.v1:be2fcd478d8951c07a5fd412", "ledger.source_cell.v1:2531e3e8f7340928e989b0ef"], "source_record_id": "ons.families_households_2025.table7.cy2023.lone_parent_dependent_children_households.households", "source_row_keys": []}, "observed_measure": {"source_concept": "ons.families_households_table7", "source_measure_id": "households", "source_name": "ons", "source_table": "Families and households in the UK 2025, Table 7: households by type", "unit": "count"}, "observed_measure_key": "ledger.observed_measure.v2:f5e97dfafe656d78d5ad97fc", "period": {"type": "calendar_year", "value": 2023}, "provenance_class": "survey_aggregate", "schema_version": "ledger.consumer_fact.v1", "semantic_fact_key": "ledger.semantic_fact.v2:716d62bd573ceb74c7b35944", "source": {"extracted_at": "2026-08-06", "extraction_method": "CellSelectorSpec and SourceRecordSpec resolved from cells", "method_notes": "Each fact carries source_record_id, source_cell_keys, and source_row_keys when available.", "raw_r2_bucket": "ledger-raw", "raw_r2_key": "raw/ons/ons-families-households-2025/2025/a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91/familiesandhouseholdsuk2025.xlsx", "raw_r2_uri": "r2://ledger-raw/raw/ons/ons-families-households-2025/2025/a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91/familiesandhouseholdsuk2025.xlsx", "source_file": "familiesandhouseholdsuk2025.xlsx", "source_name": "ons", "source_sha256": "a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91", "source_size_bytes": 209085, "source_table": "Families and households in the UK 2025, Table 7: households by type", "url": "https://www.ons.gov.uk/file?uri=/peoplepopulationandcommunity/birthsdeathsandmarriages/families/datasets/familiesandhouseholdsfamiliesandhouseholds/current/familiesandhouseholdsuk2025.xlsx", "vintage": "families_households_2025"}, "source_release_key": "ledger.source_release.v2:30b0ffd8d7245b0d6684989e", "source_series_key": "ledger.source_series.v2:9faf1c83fb31f4a881373e3c", "survey_instrument": "Labour Force Survey", "universe_constraint_set_key": "ledger.universe_constraint_set.v2:e5e64145c01a3e80897fff00", "universe_constraints": {"constraints": [{"operator": "==", "role": "filter", "value": "lone_parent_dependent_children_households", "variable": "household_type"}], "domain": "household_composition"}, "value": 1904000, "value_type": "integer"} +{"aggregate_fact_key": "ledger.aggregate_fact.v2:1f3edfb1625210d30165615f", "aggregation": {"method": "sum"}, "assertion": "observation", "concept_alignment": {"authority": "ons", "canonical_concept": "ons.households_by_type", "concept_alignment_key": "ledger.concept_alignment.v2:cf85783836063df6a5d4ade3", "evidence_notes": "Families and households in the UK, 2025 edition, Table 7 households by type, 2023 estimate, thousands.", "evidence_url": "https://www.ons.gov.uk/peoplepopulationandcommunity/birthsdeathsandmarriages/families/datasets/familiesandhouseholdsfamiliesandhouseholds", "relation": "source_label", "source_concept": "ons.families_households_table7"}, "dimension_set_key": "ledger.dimension_set.v2:90eca614baf612a013ef6626", "dimensions": {"household_type": "lone_parent_non_dependent_children_households"}, "entity": {"name": "household", "role": "resident_household"}, "geography": {"id": "K02000001", "level": "country", "vintage": "current"}, "label": "United Kingdom 2023 calendar year count ons households by type for household (household type=lone parent non dependent children households) [ons Families and households in the UK 2025, Table 7: households by type familiesandhouseholdsuk2025.xlsx families_households_2025]", "layout": {"groupby_dimension": "ons.household_type", "groupby_ordinal": 8, "groupby_value_id": "lone_parent_non_dependent_children_households", "groupby_value_label": "Non-dependent children only [note 6]", "measure_id": "households", "measure_label": "Households, 2023 estimate", "measure_ordinal": 0, "record_set_id": "ons.families_households_2025.table7.cy2023", "record_set_spec_hash": "0ea9705065c1ac17dfce8be4", "record_set_spec_id": "ons.families_households_2025.table7.cy2023.v1", "source_column_id": "households", "source_row_id": "lone_parent_non_dependent_children_households", "table_record_kind": "detail"}, "legacy_fact_key": "ledger.fact.v1:2a61e7da1ae5d62699612be5", "lineage": {"source_cell_keys": ["ledger.source_cell.v1:29c1500b656305ab825ca54d", "ledger.source_cell.v1:2531e3e8f7340928e989b0ef"], "source_record_id": "ons.families_households_2025.table7.cy2023.lone_parent_non_dependent_children_households.households", "source_row_keys": []}, "observed_measure": {"source_concept": "ons.families_households_table7", "source_measure_id": "households", "source_name": "ons", "source_table": "Families and households in the UK 2025, Table 7: households by type", "unit": "count"}, "observed_measure_key": "ledger.observed_measure.v2:f5e97dfafe656d78d5ad97fc", "period": {"type": "calendar_year", "value": 2023}, "provenance_class": "survey_aggregate", "schema_version": "ledger.consumer_fact.v1", "semantic_fact_key": "ledger.semantic_fact.v2:f748ef2f89c88332f9aaa041", "source": {"extracted_at": "2026-08-06", "extraction_method": "CellSelectorSpec and SourceRecordSpec resolved from cells", "method_notes": "Each fact carries source_record_id, source_cell_keys, and source_row_keys when available.", "raw_r2_bucket": "ledger-raw", "raw_r2_key": "raw/ons/ons-families-households-2025/2025/a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91/familiesandhouseholdsuk2025.xlsx", "raw_r2_uri": "r2://ledger-raw/raw/ons/ons-families-households-2025/2025/a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91/familiesandhouseholdsuk2025.xlsx", "source_file": "familiesandhouseholdsuk2025.xlsx", "source_name": "ons", "source_sha256": "a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91", "source_size_bytes": 209085, "source_table": "Families and households in the UK 2025, Table 7: households by type", "url": "https://www.ons.gov.uk/file?uri=/peoplepopulationandcommunity/birthsdeathsandmarriages/families/datasets/familiesandhouseholdsfamiliesandhouseholds/current/familiesandhouseholdsuk2025.xlsx", "vintage": "families_households_2025"}, "source_release_key": "ledger.source_release.v2:30b0ffd8d7245b0d6684989e", "source_series_key": "ledger.source_series.v2:9faf1c83fb31f4a881373e3c", "survey_instrument": "Labour Force Survey", "universe_constraint_set_key": "ledger.universe_constraint_set.v2:2ce43f154fad7678999d1d5c", "universe_constraints": {"constraints": [{"operator": "==", "role": "filter", "value": "lone_parent_non_dependent_children_households", "variable": "household_type"}], "domain": "household_composition"}, "value": 1089000, "value_type": "integer"} +{"aggregate_fact_key": "ledger.aggregate_fact.v2:8744ec315072dd0e31c10459", "aggregation": {"method": "sum"}, "assertion": "observation", "concept_alignment": {"authority": "ons", "canonical_concept": "ons.households_by_type", "concept_alignment_key": "ledger.concept_alignment.v2:cf85783836063df6a5d4ade3", "evidence_notes": "Families and households in the UK, 2025 edition, Table 7 households by type, 2023 estimate, thousands.", "evidence_url": "https://www.ons.gov.uk/peoplepopulationandcommunity/birthsdeathsandmarriages/families/datasets/familiesandhouseholdsfamiliesandhouseholds", "relation": "source_label", "source_concept": "ons.families_households_table7"}, "dimension_set_key": "ledger.dimension_set.v2:5677de3faee3453bcf1fb7bb", "dimensions": {"household_type": "multi_family_households"}, "entity": {"name": "household", "role": "resident_household"}, "geography": {"id": "K02000001", "level": "country", "vintage": "current"}, "label": "United Kingdom 2023 calendar year count ons households by type for household (household type=multi family households) [ons Families and households in the UK 2025, Table 7: households by type familiesandhouseholdsuk2025.xlsx families_households_2025]", "layout": {"groupby_dimension": "ons.household_type", "groupby_ordinal": 9, "groupby_value_id": "multi_family_households", "groupby_value_label": "Multi-family households [note 4] [note 11]", "measure_id": "households", "measure_label": "Households, 2023 estimate", "measure_ordinal": 0, "record_set_id": "ons.families_households_2025.table7.cy2023", "record_set_spec_hash": "0ea9705065c1ac17dfce8be4", "record_set_spec_id": "ons.families_households_2025.table7.cy2023.v1", "source_column_id": "households", "source_row_id": "multi_family_households", "table_record_kind": "detail"}, "legacy_fact_key": "ledger.fact.v1:d6d9180df2b31443fda38cfd", "lineage": {"source_cell_keys": ["ledger.source_cell.v1:b7942fa27d2a054808af7b32", "ledger.source_cell.v1:2531e3e8f7340928e989b0ef"], "source_record_id": "ons.families_households_2025.table7.cy2023.multi_family_households.households", "source_row_keys": []}, "observed_measure": {"source_concept": "ons.families_households_table7", "source_measure_id": "households", "source_name": "ons", "source_table": "Families and households in the UK 2025, Table 7: households by type", "unit": "count"}, "observed_measure_key": "ledger.observed_measure.v2:f5e97dfafe656d78d5ad97fc", "period": {"type": "calendar_year", "value": 2023}, "provenance_class": "survey_aggregate", "schema_version": "ledger.consumer_fact.v1", "semantic_fact_key": "ledger.semantic_fact.v2:72ff59ddf703db6b4b318dde", "source": {"extracted_at": "2026-08-06", "extraction_method": "CellSelectorSpec and SourceRecordSpec resolved from cells", "method_notes": "Each fact carries source_record_id, source_cell_keys, and source_row_keys when available.", "raw_r2_bucket": "ledger-raw", "raw_r2_key": "raw/ons/ons-families-households-2025/2025/a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91/familiesandhouseholdsuk2025.xlsx", "raw_r2_uri": "r2://ledger-raw/raw/ons/ons-families-households-2025/2025/a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91/familiesandhouseholdsuk2025.xlsx", "source_file": "familiesandhouseholdsuk2025.xlsx", "source_name": "ons", "source_sha256": "a89eaa3d7f519bfa949c7cfa12f531b8c7a86c704adcb70e81f49567ae724a91", "source_size_bytes": 209085, "source_table": "Families and households in the UK 2025, Table 7: households by type", "url": "https://www.ons.gov.uk/file?uri=/peoplepopulationandcommunity/birthsdeathsandmarriages/families/datasets/familiesandhouseholdsfamiliesandhouseholds/current/familiesandhouseholdsuk2025.xlsx", "vintage": "families_households_2025"}, "source_release_key": "ledger.source_release.v2:30b0ffd8d7245b0d6684989e", "source_series_key": "ledger.source_series.v2:9faf1c83fb31f4a881373e3c", "survey_instrument": "Labour Force Survey", "universe_constraint_set_key": "ledger.universe_constraint_set.v2:cfed459f0f1b30ed81d17c2e", "universe_constraints": {"constraints": [{"operator": "==", "role": "filter", "value": "multi_family_households", "variable": "household_type"}], "domain": "household_composition"}, "value": 290000, "value_type": "integer"} +{"aggregate_fact_key": "ledger.aggregate_fact.v2:2d8306be080946696b35e1ee", "aggregation": {"method": "sum"}, "assertion": "observation", "concept_alignment": {"authority": "ons", "canonical_concept": "ons.household_interest_resources", "concept_alignment_key": "ledger.concept_alignment.v2:211be3157e39540b9ed894af", "evidence_notes": "UKEA series HAXV, households (S.14) interest (D.41) resources, current price GBP million NSA; annual observation for 2023; 30 June 2026 release.", "evidence_url": "https://www.ons.gov.uk/economy/grossdomesticproductgdp/timeseries/haxv/ukea", "relation": "source_label", "source_concept": "ons.ukea_haxv"}, "dimension_set_key": "ledger.dimension_set.v2:44136fa355b3678a1146ad16", "dimensions": {}, "entity": {"name": "household", "role": "resident_household"}, "geography": {"id": "K02000001", "level": "country", "vintage": "current"}, "label": "United Kingdom 2023 calendar year sum ons household interest resources for household [ons UKEA time series HAXV: Households (S.14) interest (D.41) resources, current price GBP million NSA haxv.csv ukea_2026_06_30]", "layout": {"groupby_dimension": "ons.ukea_series", "groupby_ordinal": 0, "groupby_value_id": "haxv", "groupby_value_label": "Households interest resources (D.41), 2023", "measure_id": "amount", "measure_label": "Interest resources, current price", "measure_ordinal": 0, "record_set_id": "ons.ukea_haxv.savings_interest.cy2023", "record_set_spec_hash": "54a556f26fc3f77a4761ff2d", "record_set_spec_id": "ons.ukea_haxv.savings_interest.cy2023.v1", "source_column_id": "amount", "source_row_id": "haxv", "table_record_kind": "total"}, "legacy_fact_key": "ledger.fact.v1:26472d1cd1730a29a966ad7c", "lineage": {"source_cell_keys": ["ledger.source_cell.v1:f0675ff3dc39581313d2b30b"], "source_record_id": "ons.ukea_haxv.savings_interest.cy2023.haxv.amount", "source_row_keys": ["ledger.source_row.v1:7a1af57e305e785a371eae75"]}, "observed_measure": {"source_concept": "ons.ukea_haxv", "source_measure_id": "amount", "source_name": "ons", "source_table": "UKEA time series HAXV: Households (S.14) interest (D.41) resources, current price GBP million NSA", "unit": "gbp"}, "observed_measure_key": "ledger.observed_measure.v2:90a2a7fffdd0f18ccef24b4b", "period": {"type": "calendar_year", "value": 2023}, "provenance_class": "model_output", "schema_version": "ledger.consumer_fact.v1", "semantic_fact_key": "ledger.semantic_fact.v2:9ac263134990690ff4d4aeca", "source": {"extracted_at": "2026-08-06", "extraction_method": "CellSelectorSpec and SourceRecordSpec resolved from cells", "method_notes": "Each fact carries source_record_id, source_cell_keys, and source_row_keys when available.", "raw_r2_bucket": "ledger-raw", "raw_r2_key": "raw/ons/ons-savings-interest-income/2025/e19959488d2cfd5dcf16e58e1ea40916f6ada02a56340cc6d9099983ab3d7455/haxv.csv", "raw_r2_uri": "r2://ledger-raw/raw/ons/ons-savings-interest-income/2025/e19959488d2cfd5dcf16e58e1ea40916f6ada02a56340cc6d9099983ab3d7455/haxv.csv", "source_file": "haxv.csv", "source_name": "ons", "source_sha256": "e19959488d2cfd5dcf16e58e1ea40916f6ada02a56340cc6d9099983ab3d7455", "source_size_bytes": 3517, "source_table": "UKEA time series HAXV: Households (S.14) interest (D.41) resources, current price GBP million NSA", "url": "https://www.ons.gov.uk/generator?format=csv&uri=/economy/grossdomesticproductgdp/timeseries/haxv/ukea", "vintage": "ukea_2026_06_30"}, "source_release_key": "ledger.source_release.v2:b751c41b3a24bf9318fc5ef5", "source_series_key": "ledger.source_series.v2:eba1daee637269097aae41d2", "universe_constraint_set_key": "ledger.universe_constraint_set.v2:fa6e32cc24b49ed112373325", "universe_constraints": {"domain": "national_accounts"}, "value": 86040000000, "value_type": "integer"} +{"aggregate_fact_key": "ledger.aggregate_fact.v2:13db6458448be6778d734c6d", "aggregation": {"method": "sum"}, "assertion": "observation", "concept_alignment": {"authority": "ons", "canonical_concept": "ons.pse_headcount_total_public_sector", "concept_alignment_key": "ledger.concept_alignment.v2:3f939abcfd2534dcb3d09440", "evidence_notes": "Public sector employment reference table, March 2026 edition, Table 1 (public sector employment by sector classification, headcount, UK, thousands), row Dec 2023, series G7AU (Total public sector).", "evidence_url": "https://www.ons.gov.uk/employmentandlabourmarket/peopleinwork/publicsectorpersonnel/datasets/publicsectoremploymentreferencetable", "relation": "source_label", "source_concept": "ons.g7au"}, "dimension_set_key": "ledger.dimension_set.v2:44136fa355b3678a1146ad16", "dimensions": {}, "entity": {"name": "person", "role": "public_sector_employee"}, "geography": {"id": "K02000001", "level": "country", "vintage": "current"}, "label": "United Kingdom 2023-12 month count ons pse headcount total public sector for person [ons Public sector employment reference table, UK, March 2026 edition pse-reference-table-march2026.xlsx pse_march_2026]", "layout": {"groupby_dimension": "ons.pse_sector_classification", "groupby_ordinal": 0, "groupby_value_id": "dec2023", "groupby_value_label": "Dec 2023", "measure_id": "total_public_sector", "measure_label": "Public sector employment headcount, Total public sector, Dec 2023", "measure_ordinal": 4, "record_set_id": "ons.pse_march2026.table1.dec2023", "record_set_spec_hash": "d3cbbb78d9321555f17c693e", "record_set_spec_id": "ons.pse_march2026.table1.dec2023.v1", "source_column_id": "total_public_sector", "source_row_id": "dec2023", "table_record_kind": "total"}, "legacy_fact_key": "ledger.fact.v1:29e8f77ae80ecb7a1c08ef70", "lineage": {"source_cell_keys": ["ledger.source_cell.v1:579c63ac34c0bf18b037453c", "ledger.source_cell.v1:6bc94cddc923c5f1bc1da995"], "source_record_id": "ons.pse_march2026.table1.dec2023.dec2023.total_public_sector", "source_row_keys": []}, "observed_measure": {"source_concept": "ons.g7au", "source_measure_id": "total_public_sector", "source_name": "ons", "source_table": "Public sector employment reference table, UK, March 2026 edition", "unit": "count"}, "observed_measure_key": "ledger.observed_measure.v2:f471420c3faf6b14a46a2a04", "period": {"type": "month", "value": "2023-12"}, "provenance_class": "survey_aggregate", "schema_version": "ledger.consumer_fact.v1", "semantic_fact_key": "ledger.semantic_fact.v2:95517ab43857e313e352e0d7", "source": {"extracted_at": "2026-08-07", "extraction_method": "CellSelectorSpec and SourceRecordSpec resolved from cells", "method_notes": "Each fact carries source_record_id, source_cell_keys, and source_row_keys when available.", "raw_r2_bucket": "ledger-raw", "raw_r2_key": "raw/ons/ons-public-sector-employment-2026/2026/aa04454e77ae1a45d26e7a89801a946721b9c8f00b7760cf72f4edaa2482509c/pse-reference-table-march2026.xlsx", "raw_r2_uri": "r2://ledger-raw/raw/ons/ons-public-sector-employment-2026/2026/aa04454e77ae1a45d26e7a89801a946721b9c8f00b7760cf72f4edaa2482509c/pse-reference-table-march2026.xlsx", "source_file": "pse-reference-table-march2026.xlsx", "source_name": "ons", "source_sha256": "aa04454e77ae1a45d26e7a89801a946721b9c8f00b7760cf72f4edaa2482509c", "source_size_bytes": 225893, "source_table": "Public sector employment reference table, UK, March 2026 edition", "url": "https://www.ons.gov.uk/file?uri=/employmentandlabourmarket/peopleinwork/publicsectorpersonnel/datasets/publicsectoremploymentreferencetable/march2026/datasets.xlsx", "vintage": "pse_march_2026"}, "source_release_key": "ledger.source_release.v2:1f9022736d3d7824c98d8415", "source_series_key": "ledger.source_series.v2:558bdb2e8110d0edbc8ade29", "survey_instrument": "Quarterly Public Sector Employment Survey", "universe_constraint_set_key": "ledger.universe_constraint_set.v2:3a69adaf2f3734585a77b8eb", "universe_constraints": {"domain": "public_sector_employment"}, "value": 6089000, "value_type": "integer"} diff --git a/packages/microcosm-build/tests/test_uk_target_references.py b/packages/microcosm-build/tests/test_uk_target_references.py index dbf384359..02bff1893 100644 --- a/packages/microcosm-build/tests/test_uk_target_references.py +++ b/packages/microcosm-build/tests/test_uk_target_references.py @@ -9,12 +9,22 @@ import json from importlib import resources as importlib_resources +from pathlib import Path + +import numpy as np +import pandas as pd from microcosm.build.country_spec import load_country_spec from microcosm.build.ledger_targets import compile_ledger_target_references +from microcosm.calibrate.matrix import build_constraint_matrix +from microcosm.frame import EntitySchema, Frame, WeightKind, Weights ACTIVE_REFERENCE_COUNT = 13 +FIXTURE_FEED_ROWS = ( + Path(__file__).parent / "fixtures" / "uk_target_reference_feed_rows.jsonl" +) + def _load_uk_resource(name: str) -> dict: return json.loads( @@ -62,7 +72,13 @@ def test_uk_target_references_follow_contract_derivation_rules() -> None: assert reference["measure"] == binding["metric_name"] assert reference["family"] == target["family"] assert reference["period"] == 2023 - assert reference["metadata"] == {"contract_target_id": contract_target_id} + assert reference["metadata"] == { + "contract_target_id": contract_target_id, + "measure_kind": "prepared_column", + } + # The measure is a prepared column, so the pointed-to contract binding + # must carry what the microcosm#622 materializer needs to prepare it. + assert binding.get("value_variable"), contract_target_id def test_uk_target_references_compile_from_real_staged_feed_rows() -> None: @@ -117,6 +133,78 @@ def test_uk_target_references_compile_from_real_staged_feed_rows() -> None: ) +def test_uk_target_references_constrain_a_frame_with_prepared_columns() -> None: + """The full active subset compiles into constraint rows, end to end. + + Measures name prepared columns (the US prepared-indicator-column doctrine): + the microcosm#622 materializer owns building them from the contract + bindings, so this test hand-prepares one column per measure on the + reference's entity table and proves the compiled registry constrains a + household-weighted frame with zero skipped targets and exact row + aggregates. + """ + + spec = load_country_spec("uk") + references = spec.target_references + feed_rows = [ + json.loads(line) + for line in FIXTURE_FEED_ROWS.read_text().splitlines() + if line.strip() + ] + + registry = compile_ledger_target_references(feed_rows, references, country="uk") + assert len(registry.specs) == ACTIVE_REFERENCE_COUNT + + n_households = 3 + weights = np.array([10.0, 20.0, 30.0]) + household_columns: dict[str, np.ndarray] = {} + person_columns: dict[str, np.ndarray] = {} + expected_aggregates: dict[str, float] = {} + for index, compiled in enumerate(registry.specs): + column = np.array([index + 1.0, 2.0 * (index + 1.0), 0.0]) + columns = ( + person_columns if compiled.entity == "person" else household_columns + ) + columns[compiled.measure] = column + expected_aggregates[f"{compiled.name}@{compiled.period}"] = float( + (column * weights).sum() + ) + + household_ids = np.arange(n_households, dtype="int64") + frame = Frame( + { + "person": pd.DataFrame( + { + "person_id": household_ids, + "person_household_id": household_ids, + **person_columns, + } + ), + "household": pd.DataFrame( + {"household_id": household_ids, **household_columns} + ), + }, + EntitySchema(group_entities=("household",)), + {"household": Weights(values=weights, kind=WeightKind.DESIGN)}, + ) + + problem = build_constraint_matrix(frame, registry.to_target_set()) + + assert problem.skipped == () + assert len(problem.names) == ACTIVE_REFERENCE_COUNT + achieved = problem.matrix @ problem.initial_weights.values + for name, estimate in zip(problem.names, achieved, strict=True): + assert estimate == expected_aggregates[name], name + fact_values_by_name = { + f"{compiled.name}@{compiled.period}": compiled.value + for compiled in registry.specs + } + for name, target_value in zip( + problem.names, problem.target_vector, strict=True + ): + assert target_value == fact_values_by_name[name], name + + def _real_uk_consumer_fact_rows() -> list[dict]: """Public rows copied from .codex-work/consumer_facts_uk.jsonl.""" From 9c0fe4d0d9c17eb490688446921bd625df38ed6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20Juaristi?= <127882282+juaristi22@users.noreply.github.com> Date: Wed, 19 Aug 2026 17:08:38 +0200 Subject: [PATCH 08/10] Register the two contract resources in #717's tuple pin as well The SPI-spine PR added a second test pinning the UK resource tuple; both pins now carry uk_national_targets.json and target_references.json. Co-Authored-By: Claude Fable 5 --- packages/microcosm-build/tests/test_country_spec.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/microcosm-build/tests/test_country_spec.py b/packages/microcosm-build/tests/test_country_spec.py index 81ebbee39..3c30014ff 100644 --- a/packages/microcosm-build/tests/test_country_spec.py +++ b/packages/microcosm-build/tests/test_country_spec.py @@ -282,6 +282,8 @@ def test_spi_spine_adds_no_country_package_resources(self) -> None: "release_input_coverage_manifest.json", "was_wealth_support_bounds.json", "uk_local_target_census.json", + "uk_national_targets.json", + "target_references.json", ) def test_uk_source_manifest_loads_eighteen_stages(self) -> None: From ce7aab12f55f8d8ae933c2d6ec06e2cc17bb8496 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20Juaristi?= <127882282+juaristi22@users.noreply.github.com> Date: Wed, 19 Aug 2026 17:08:38 +0200 Subject: [PATCH 09/10] Refuse empty selector lists and document resolve-or-defer deactivation Review response (vahid): an empty membership or dimension-pin list matches nothing while reading like match-anything - both now raise at resolve time. The strict-typed-equality footgun (a float 5.0 pin vs an int 5 fact deactivates the target instead of erroring) is documented where the future debugger will look: the _dimension_values_match docstring and the target_references.json description both point at the authoring-run membership report for unexpectedly inactive targets. Co-Authored-By: Claude Fable 5 --- .../src/microcosm/build/ledger_targets.py | 32 ++++++++++++++++- .../microcosm/build/uk/target_references.json | 2 +- .../tests/test_ledger_targets.py | 34 +++++++++++++++++++ 3 files changed, 66 insertions(+), 2 deletions(-) diff --git a/packages/microcosm-build/src/microcosm/build/ledger_targets.py b/packages/microcosm-build/src/microcosm/build/ledger_targets.py index 8e1ec4017..cfcd41d50 100644 --- a/packages/microcosm-build/src/microcosm/build/ledger_targets.py +++ b/packages/microcosm-build/src/microcosm/build/ledger_targets.py @@ -1033,7 +1033,14 @@ def _unique_facts(facts: Iterable[object]) -> tuple[object, ...]: def _fact_matches_selector(fact: object, selector: Mapping[str, object]) -> bool: - """Return whether a consumer fact satisfies a structured reference selector.""" + """Return whether a consumer fact satisfies a structured reference selector. + + A list-valued scalar key matches by membership; an empty list is refused + rather than treated as match-nothing, because it reads like match-anything. + Note ``dimensions: []`` is NOT an empty membership list — it is the + list-form dimensions selector's exact name-set match for the dimensionless + total row (see :func:`_dimensions_match`). + """ for key, expected in selector.items(): if key == "dimensions": @@ -1048,6 +1055,12 @@ def _fact_matches_selector(fact: object, selector: Mapping[str, object]) -> bool continue candidates = _selector_candidates(fact, str(key)) if isinstance(expected, (list, tuple)): + if not expected: + raise ValueError( + f"Ledger fact selector field {key!r} is an empty list: an " + "empty membership list matches nothing while reading like " + "match-anything. Pin at least one value or drop the field." + ) if not any(str(item) in candidates for item in expected): return False continue @@ -1123,12 +1136,29 @@ def _dimensions_match(fact: object, expected: object) -> bool: def _dimension_values_match(fact: object, expected: object) -> bool: + """Match dimension-value pins with strict typed equality. + + A pin whose type disagrees with the fact's dimension value (float ``5.0`` + against int ``5``, ``"5"`` against ``5``) does not error — the fact simply + fails to match, so under a resolves-or-defers activation rule the target + quietly drops out of the active subset. When a target is unexpectedly + inactive, check the authoring-run membership report before suspecting the + feed. Empty pin lists are refused for the same reason as empty membership + lists in :func:`_fact_matches_selector`. + """ + if not isinstance(expected, Mapping): raise ValueError( "Ledger fact selector field 'dimension_values' must be a mapping." ) dimensions = _dimensions(fact) for key, expected_value in expected.items(): + if isinstance(expected_value, list) and not expected_value: + raise ValueError( + f"dimension_values pin {key!r} is an empty list: an empty pin " + "list matches nothing while reading like match-anything. Pin " + "at least one value or drop the dimension." + ) if key not in dimensions: return False actual_value = dimensions[key] diff --git a/packages/microcosm-build/src/microcosm/build/uk/target_references.json b/packages/microcosm-build/src/microcosm/build/uk/target_references.json index 21741acdb..eb524850a 100644 --- a/packages/microcosm-build/src/microcosm/build/uk/target_references.json +++ b/packages/microcosm-build/src/microcosm/build/uk/target_references.json @@ -1,6 +1,6 @@ { "country": "uk", - "description": "UK active-subset Ledger target references for the national 2023 spine. Rows are generated from uk_national_targets.json: name is the contract target_id; ledger_selector is the contract selector plus geography_level country for the first national activation; entity is from_entity, then map_to, then household; measure is bindings.policyengine.metric_name; family is the contract family; period is 2023; metadata.contract_target_id points back to the contract row. Observed values stay in Ledger facts and resolve by identity only. Deferred classes are recorded in .codex-work/membership_report.json: no fact at or before 2023, multi-fact sum resolution pending, source-projection policy pending, country-level geography ambiguity, or missing/non-finite fact values. Measures name prepared columns, not raw model variables: each reference's measure is the slash-named column the microcosm#622 UK materializer must prepare on the reference's entity table from the contract binding payload (value_variable plus filters/conditions) referenced by metadata.contract_target_id, following the US prepared-indicator-column doctrine (target_spec_from_ledger_reference: count-like facts are sums of prepared indicator columns; the JCT materializer names household columns after their targets). metadata.measure_kind records this on every row.", + "description": "UK active-subset Ledger target references for the national 2023 spine. Rows are generated from uk_national_targets.json: name is the contract target_id; ledger_selector is the contract selector plus geography_level country for the first national activation; entity is from_entity, then map_to, then household; measure is bindings.policyengine.metric_name; family is the contract family; period is 2023; metadata.contract_target_id points back to the contract row. Observed values stay in Ledger facts and resolve by identity only. Deferred classes are recorded in .codex-work/membership_report.json: no fact at or before 2023, multi-fact sum resolution pending, source-projection policy pending, country-level geography ambiguity, or missing/non-finite fact values. Measures name prepared columns, not raw model variables: each reference's measure is the slash-named column the microcosm#622 UK materializer must prepare on the reference's entity table from the contract binding payload (value_variable plus filters/conditions) referenced by metadata.contract_target_id, following the US prepared-indicator-column doctrine (target_spec_from_ledger_reference: count-like facts are sums of prepared indicator columns; the JCT materializer names household columns after their targets). metadata.measure_kind records this on every row. Activation is resolve-or-defer, not resolve-or-fail: a dimension pin whose type disagrees with the fact's value (float 5.0 vs int 5) deactivates the target rather than erroring - when a target is unexpectedly inactive, check the authoring-run membership report on the PR before suspecting the feed. Empty pin or membership lists are refused at resolve time.", "allowed_value_operations": [ "identity" ], diff --git a/packages/microcosm-build/tests/test_ledger_targets.py b/packages/microcosm-build/tests/test_ledger_targets.py index c07bd2f5c..9e1d55e99 100644 --- a/packages/microcosm-build/tests/test_ledger_targets.py +++ b/packages/microcosm-build/tests/test_ledger_targets.py @@ -752,6 +752,40 @@ def test_dimension_values_require_present_dimension(self) -> None: country="us", ) + def test_empty_membership_list_raises_instead_of_matching_nothing(self) -> None: + reference = LedgerTargetReference( + name="empty membership selector", + ledger_selector={"source_measure_id": []}, + entity="tax_unit", + measure="adjusted_gross_income", + period=2023, + family="irs_soi", + ) + + with pytest.raises(ValueError, match="empty list"): + compile_ledger_target_references( + [_consumer_fact_row()], + [reference], + country="us", + ) + + def test_empty_dimension_values_pin_list_raises(self) -> None: + reference = LedgerTargetReference( + name="empty pin list selector", + ledger_selector={"dimension_values": {"band": []}}, + entity="tax_unit", + measure="adjusted_gross_income", + period=2023, + family="irs_soi", + ) + + with pytest.raises(ValueError, match="empty pin"): + compile_ledger_target_references( + [_consumer_fact_row(dimensions={"band": "A"})], + [reference], + country="us", + ) + def test_empty_dimensions_list_matches_dimensionless_fact(self) -> None: reference = LedgerTargetReference( name="dimensionless selector", From 1ad49d52a21c5c7d7d7747d508f3cfef2e45310d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20Juaristi?= <127882282+juaristi22@users.noreply.github.com> Date: Wed, 19 Aug 2026 17:48:59 +0200 Subject: [PATCH 10/10] Carry the uk-extra lock regen from the parallel branch integration A concurrent push folded main into this branch as a merge and included the uv.lock regen for microcosm-frame's uk extra (stale since #717; CI syncs without --locked so it stayed green). The merge's content is otherwise identical to this rebased line, which supersedes it. Co-Authored-By: Claude Fable 5 --- uv.lock | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/uv.lock b/uv.lock index acd314a1c..01fdf10db 100644 --- a/uv.lock +++ b/uv.lock @@ -797,6 +797,9 @@ policyengine = [ { name = "microunit" }, { name = "policyengine-us" }, ] +uk = [ + { name = "policyengine-uk" }, +] us = [ { name = "microunit" }, ] @@ -814,10 +817,11 @@ requires-dist = [ { name = "microunit", marker = "extra == 'us'", specifier = ">=0.1.0" }, { name = "numpy", specifier = ">=2" }, { name = "pandas", specifier = ">=2.3" }, + { name = "policyengine-uk", marker = "extra == 'uk'", specifier = ">=2.88" }, { name = "policyengine-us", marker = "extra == 'policyengine'", specifier = ">=1.745.0,<2" }, { name = "tables", marker = "extra == 'axiom'", specifier = ">=3" }, ] -provides-extras = ["us", "policyengine", "axiom"] +provides-extras = ["us", "policyengine", "uk", "axiom"] [package.metadata.requires-dev] dev = [