From 3d01aab2a8e6eef29a9a9e4914f59a7a1b5070dc Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 30 Oct 2026 18:34:23 -0400 Subject: [PATCH 1/2] Correct programme registry agencies and national coverage Pin the six sourced metadata corrections and verify that Core preserves agency and coverage strings. Co-Authored-By: Claude Opus 5.5 --- changelog.d/2696.fixed.md | 1 + policyengine_uk/programs.yaml | 16 +++---- .../tests/test_program_registry.py | 42 +++++++++++++++++++ 3 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 changelog.d/2696.fixed.md diff --git a/changelog.d/2696.fixed.md b/changelog.d/2696.fixed.md new file mode 100644 index 0000000000..c7b47bc94e --- /dev/null +++ b/changelog.d/2696.fixed.md @@ -0,0 +1 @@ +The programme registry identifies the correct responsible bodies and nations for Scottish income tax, tax credits, the Energy Price Guarantee, Council Tax, Council Tax Reduction and Winter Fuel Payment. diff --git a/policyengine_uk/programs.yaml b/policyengine_uk/programs.yaml index ed22040b61..1bdc217c07 100644 --- a/policyengine_uk/programs.yaml +++ b/policyengine_uk/programs.yaml @@ -375,13 +375,13 @@ programs: name: Tax credits full_name: Tax Credits (Working Tax Credit and Child Tax Credit) category: Benefits - agency: DWP + agency: HMRC status: complete coverage: UK variable: tax_credits parameter_prefix: gov.dwp.tax_credits verified_start_year: 2022 - notes: Legacy benefit being replaced by Universal Credit + notes: HMRC administered Working Tax Credit and Child Tax Credit until they ended on 5 April 2025 - id: sda name: SDA @@ -400,11 +400,11 @@ programs: category: Benefits agency: DWP status: complete - coverage: UK + coverage: England, Wales and Northern Ireland variable: winter_fuel_payment parameter_prefix: gov.dwp.winter_fuel_payment verified_start_year: 2022 - notes: Great Britain to winter 2023-24, then England and Wales; Northern Ireland's mirror scheme uses the same parameters. From winter 2025-26 paid to everyone of pensionable age and recovered by the winter fuel payment charge (income tax) + notes: Great Britain to winter 2023-24, then England and Wales; Northern Ireland's mirror scheme uses the same parameters. The Scottish Government replaced it with Pension Age Winter Heating Payment from winter 2024-25. From winter 2025-26 HMRC recovers payments from higher-income recipients through the winter fuel payment charge (income tax) - id: ssmg name: Sure Start Maternity Grant @@ -572,7 +572,7 @@ programs: category: Taxes agency: Local status: complete - coverage: UK + coverage: Great Britain variable: council_tax verified_start_year: 2022 @@ -582,7 +582,7 @@ programs: category: Benefits agency: Local status: partial - coverage: UK + coverage: Great Britain variable: council_tax_reduction parameter_prefix: gov.local_authorities verified_start_year: 2013 @@ -606,7 +606,7 @@ programs: name: Energy Price Guarantee full_name: Energy Price Guarantee category: Benefits - agency: Ofgem + agency: DESNZ status: partial coverage: UK parameter_prefix: gov.ofgem @@ -635,7 +635,7 @@ programs: name: Scottish income tax full_name: Scottish Income Tax Rates category: Taxes - agency: Revenue Scotland + agency: HMRC status: complete coverage: Scotland verified_start_year: 2019 diff --git a/policyengine_uk/tests/test_program_registry.py b/policyengine_uk/tests/test_program_registry.py index f4214066d8..668a554210 100644 --- a/policyengine_uk/tests/test_program_registry.py +++ b/policyengine_uk/tests/test_program_registry.py @@ -2,6 +2,7 @@ import pytest import yaml +from hypothesis import given, settings, strategies as st from policyengine_core.parameters import ParameterNode from policyengine_uk import CountryTaxBenefitSystem @@ -54,3 +55,44 @@ def test_benefit_cap_does_not_advertise_unrelated_parameters(tax_benefit_system) advertised.get_child("non_single.outside_london") is benefit_cap.non_single.outside_london ) + + +@pytest.mark.parametrize( + "program_id, field, expected", + [ + ("scottish_income_tax", "agency", "HMRC"), + ("tax_credits", "agency", "HMRC"), + ("energy_price_guarantee", "agency", "DESNZ"), + ("council_tax", "coverage", "Great Britain"), + ("council_tax_reduction", "coverage", "Great Britain"), + ( + "winter_fuel_payment", + "coverage", + "England, Wales and Northern Ireland", + ), + ], + ids=lambda value: value, +) +def test_program_agency_and_coverage(program_id, field, expected): + """The registry identifies the administering body and nations (#2696).""" + programs = [p for p in PROGRAMS if p["id"] == program_id] + assert len(programs) == 1 + assert programs[0][field] == expected + + +@settings(max_examples=len(PROGRAMS), database=None, derandomize=True) +@given(program_id=st.sampled_from(tuple(p["id"] for p in PROGRAMS))) +def test_program_metadata_survives_loading(tax_benefit_system, program_id): + """Core exposes every program's agency and coverage strings unchanged.""" + registry_program = next(p for p in PROGRAMS if p["id"] == program_id) + loaded_programs = [ + p + for p in tax_benefit_system.modelled_policies["programs"] + if p["id"] == program_id + ] + assert len(loaded_programs) == 1 + for field in ("agency", "coverage"): + value = loaded_programs[0][field] + assert isinstance(value, str) + assert value + assert value == registry_program[field] From 4c47db4c92880c79044236714610d16c5eb265aa Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 30 Oct 2026 18:56:21 -0400 Subject: [PATCH 2/2] Test the dates in the corrected programme notes Co-Authored-By: Claude Opus 5.5 --- policyengine_uk/tests/test_program_registry.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/policyengine_uk/tests/test_program_registry.py b/policyengine_uk/tests/test_program_registry.py index 668a554210..2ff5fe25a3 100644 --- a/policyengine_uk/tests/test_program_registry.py +++ b/policyengine_uk/tests/test_program_registry.py @@ -80,6 +80,21 @@ def test_program_agency_and_coverage(program_id, field, expected): assert programs[0][field] == expected +@pytest.mark.parametrize( + "program_id, date", + [ + ("tax_credits", "5 April 2025"), + ("winter_fuel_payment", "from winter 2024-25"), + ], + ids=lambda value: value, +) +def test_program_notes_state_when_the_scheme_changed(program_id, date): + """The notes keep each programme's sourced end or replacement date (#2696).""" + programs = [p for p in PROGRAMS if p["id"] == program_id] + assert len(programs) == 1 + assert date in programs[0]["notes"] + + @settings(max_examples=len(PROGRAMS), database=None, derandomize=True) @given(program_id=st.sampled_from(tuple(p["id"] for p in PROGRAMS))) def test_program_metadata_survives_loading(tax_benefit_system, program_id):