From 75b2123c795c39a3ac1d153e237a4388d3649367 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sat, 31 Oct 2026 08:42:16 -0400 Subject: [PATCH 1/5] =?UTF-8?q?Pay=20the=202022=20=C2=A3150=20to=20Council?= =?UTF-8?q?=20Tax=20Reduction=20recipients=20in=20any=20band?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Scotland's Cost of Living Award and Wales's Cost of Living Support Scheme paid bands A to D and Council Tax Reduction recipients in any band. Co-Authored-By: Claude Opus 5.5 --- changelog.d/2766.fixed.md | 1 + .../gov/treasury/cost-of-living-payments.md | 9 ++++- .../council_tax_reduction_countries.yaml | 14 +++++++ policyengine_uk/programs.yaml | 13 ++++--- .../energy_bills_rebate/council_tax_rebate.py | 38 +++++++++++++------ 5 files changed, 56 insertions(+), 19 deletions(-) create mode 100644 changelog.d/2766.fixed.md create mode 100644 policyengine_uk/parameters/gov/treasury/energy_bills_rebate/council_tax_rebate/council_tax_reduction_countries.yaml diff --git a/changelog.d/2766.fixed.md b/changelog.d/2766.fixed.md new file mode 100644 index 0000000000..25b804cc61 --- /dev/null +++ b/changelog.d/2766.fixed.md @@ -0,0 +1 @@ +Pay the 2022 £150 to Council Tax Reduction recipients in any council tax band in Scotland and Wales, as Scotland's Cost of Living Award and Wales's Cost of Living Support Scheme did. diff --git a/docs/book/programs/gov/treasury/cost-of-living-payments.md b/docs/book/programs/gov/treasury/cost-of-living-payments.md index 6b20bafc34..fbba7f11d7 100644 --- a/docs/book/programs/gov/treasury/cost-of-living-payments.md +++ b/docs/book/programs/gov/treasury/cost-of-living-payments.md @@ -17,8 +17,13 @@ spike in domestic energy prices. Two strands: April 2022. The guidance asked billing authorities to pay from April and set 30 September 2022 as the deadline for the payments the government would reconcile (paragraph 7). Scotland and Wales paid their own £150 - awards to bands A–D, and also to Council Tax Reduction recipients in any - band, which the model leaves out. Northern Ireland levies domestic rates, + awards to bands A–D and to Council Tax Reduction recipients in any band; + the model tests `council_tax_reduction` for the year, not receipt on 14 + February 2022 (Scotland) or 15 February 2022 (Wales). All three nations + also paid band E homes charged at band D under the disabled band + reduction. The model has no input for that reduction, so it pays those + homes only if they qualify through Council Tax Reduction. Northern + Ireland levies domestic rates, not council tax, and had no Council Tax Rebate, so the model pays none there whatever the household's council tax band (the enhanced FRS gives every Northern Ireland household band A, the default policyengine-uk-data diff --git a/policyengine_uk/parameters/gov/treasury/energy_bills_rebate/council_tax_rebate/council_tax_reduction_countries.yaml b/policyengine_uk/parameters/gov/treasury/energy_bills_rebate/council_tax_rebate/council_tax_reduction_countries.yaml new file mode 100644 index 0000000000..2308f69859 --- /dev/null +++ b/policyengine_uk/parameters/gov/treasury/energy_bills_rebate/council_tax_rebate/council_tax_reduction_countries.yaml @@ -0,0 +1,14 @@ +description: Countries that paid the 2022 £150 to Council Tax Reduction recipients in any council tax band. Scotland's Cost of Living Award and Wales's Cost of Living Support Scheme paid them, while England's Council Tax Rebate went by band alone. +values: + 0001-01-01: + value: + - SCOTLAND + - WALES + reference: + - title: Local Government Finance Circular 2/2022, paragraphs 6 and 10 + href: https://www.gov.scot/publications/local-government-finance-circular-2-2022-guidance-to-local-authorities-april-2022-cost-of-living-award/ + - title: Cost of Living Support Scheme guide for local authorities, condition A + href: https://www.gov.wales/cost-living-support-scheme-guide-local-authorities-html +metadata: + unit: list + label: Countries paying Council Tax Reduction recipients in any band diff --git a/policyengine_uk/programs.yaml b/policyengine_uk/programs.yaml index c1a8bd6c76..5b25a201a1 100644 --- a/policyengine_uk/programs.yaml +++ b/policyengine_uk/programs.yaml @@ -614,12 +614,13 @@ programs: verified_end_year: 2023 notes: >- Temporary program, ended 2023. The £150 Council Tax Rebate in bands A to - D in Great Britain (none in Northern Ireland, which has domestic rates), - the £400 Energy Bills Support Scheme, and Northern Ireland's £200 - Alternative Fuel Payment. Leaves out the Scottish and Welsh £150 for - Council Tax Reduction recipients in bands E and above, England's - discretionary fund, Great Britain's Alternative Fuel Payment and the - alternative funding schemes. + D in Great Britain and for Council Tax Reduction recipients in any band + in Scotland and Wales (none in Northern Ireland, which has domestic + rates), the £400 Energy Bills Support Scheme, and Northern Ireland's + £200 Alternative Fuel Payment. Leaves out band E homes charged at band D + under the disabled band reduction, Scotland's payments to exempt + dwellings, England's discretionary fund, Great Britain's Alternative + Fuel Payment and the alternative funding schemes. - id: household_energy_payment name: Household Energy Payment diff --git a/policyengine_uk/variables/gov/treasury/energy_bills_rebate/council_tax_rebate.py b/policyengine_uk/variables/gov/treasury/energy_bills_rebate/council_tax_rebate.py index 8dc7ac15b0..cf1fc88144 100644 --- a/policyengine_uk/variables/gov/treasury/energy_bills_rebate/council_tax_rebate.py +++ b/policyengine_uk/variables/gov/treasury/energy_bills_rebate/council_tax_rebate.py @@ -6,12 +6,21 @@ class ebr_council_tax_rebate(Variable): documentation = ( "Council Tax discount under the Energy Bills Rebate. England's £150 " "Council Tax Rebate went to households in bands A to D (billing " - "authority guidance, paragraphs 2 and 11), and Scotland and Wales " - "paid their own £150 awards to the same bands. Northern Ireland " - "levies domestic rates, not council tax, and had no Council Tax " - "Rebate; its households received the £600 Energy Bills Support " - "Scheme payment. The model doesn't pay the Scottish and Welsh awards " - "to Council Tax Reduction recipients in bands E and above." + "authority guidance, paragraphs 2 and 11). Scotland's Cost of Living " + "Award and Wales's Cost of Living Support Scheme paid £150 to bands A " + "to D and to Council Tax Reduction recipients in any band (Local " + "Government Finance Circular 2/2022, paragraphs 6, 10 and 12; Welsh " + "guide, conditions A and B). Northern Ireland levies domestic rates, " + "not council tax, and had no Council Tax Rebate; its households " + "received the £600 Energy Bills Support Scheme payment. The test " + "reads council_tax_reduction for the year, not receipt on 14 February " + "2022 (Scotland) or 15 February 2022 (Wales). The model has no input " + "for the disabled band reduction, so it doesn't pay band E homes " + "charged at band D (England's paragraph 11(i), Scotland's paragraph " + "12, Wales's condition B) unless they qualify through Council Tax " + "Reduction. It also leaves out Scotland's payments to exempt dwellings " + "(paragraphs 16 to 18), and second adult rebate, which it doesn't " + "simulate." ) entity = Household definition_period = YEAR @@ -25,15 +34,22 @@ class ebr_council_tax_rebate(Variable): ) def formula(household, period, parameters): - ctr = parameters(period).gov.treasury.energy_bills_rebate.council_tax_rebate + p = parameters(period).gov.treasury.energy_bills_rebate.council_tax_rebate ct_band = household("council_tax_band", period) ct_band_values = ct_band.possible_values - eligible = np.any( - np.array([ct_band == getattr(ct_band_values, band) for band in ctr.bands]), + in_qualifying_band = np.any( + np.array([ct_band == getattr(ct_band_values, band) for band in p.bands]), axis=0, ) + # Scotland and Wales also paid Council Tax Reduction recipients in any + # band; England went by band alone. + country = household("country", period) + pays_reduction_recipients = np.isin( + country.decode_to_str(), list(p.council_tax_reduction_countries) + ) + receives_reduction = household("council_tax_reduction", period) > 0 + eligible = in_qualifying_band | (pays_reduction_recipients & receives_reduction) # Northern Ireland has no council tax bands, so its input band means # nothing here (the enhanced FRS gives every NI household band A). - country = household("country", period) has_council_tax = country != country.possible_values.NORTHERN_IRELAND - return has_council_tax * eligible * ctr.amount + return has_council_tax * eligible * p.amount From 00e96fc85c0d26b74be4329a16e2299893e0ba7c Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sat, 31 Oct 2026 08:50:17 -0400 Subject: [PATCH 2/5] Test the Council Tax Reduction route per nation Co-Authored-By: Claude Opus 5.5 --- .../gov/treasury/cost-of-living-payments.md | 3 + policyengine_uk/programs.yaml | 2 +- .../council_tax_rebate.yaml | 322 ++++++++++++++++++ ...rebate_council_tax_reduction_properties.py | 202 +++++++++++ .../energy_bills_rebate/council_tax_rebate.py | 6 +- 5 files changed, 531 insertions(+), 4 deletions(-) create mode 100644 policyengine_uk/tests/test_energy_bills_rebate_council_tax_reduction_properties.py diff --git a/docs/book/programs/gov/treasury/cost-of-living-payments.md b/docs/book/programs/gov/treasury/cost-of-living-payments.md index fbba7f11d7..3affeda8d3 100644 --- a/docs/book/programs/gov/treasury/cost-of-living-payments.md +++ b/docs/book/programs/gov/treasury/cost-of-living-payments.md @@ -53,6 +53,9 @@ PolicyEngine models these via: - `energy_bills_credit.yaml` — a yearly top-up, zero by default, kept for reforms - `council_tax_rebate/bands.yaml` — qualifying CT bands (A–D) + - `council_tax_rebate/council_tax_reduction_countries.yaml` — countries + that also paid Council Tax Reduction recipients in any band (Scotland + and Wales) - `council_tax_rebate/amount.yaml` — £150 in 2022-23 and nothing in any other year diff --git a/policyengine_uk/programs.yaml b/policyengine_uk/programs.yaml index 5b25a201a1..d310a5d02e 100644 --- a/policyengine_uk/programs.yaml +++ b/policyengine_uk/programs.yaml @@ -618,7 +618,7 @@ programs: in Scotland and Wales (none in Northern Ireland, which has domestic rates), the £400 Energy Bills Support Scheme, and Northern Ireland's £200 Alternative Fuel Payment. Leaves out band E homes charged at band D - under the disabled band reduction, Scotland's payments to exempt + under the disabled band reduction, Scotland's rules for exempt dwellings, England's discretionary fund, Great Britain's Alternative Fuel Payment and the alternative funding schemes. diff --git a/policyengine_uk/tests/policy/baseline/gov/treasury/energy_bills_rebate/council_tax_rebate.yaml b/policyengine_uk/tests/policy/baseline/gov/treasury/energy_bills_rebate/council_tax_rebate.yaml index a4cd8dc68a..7bf84b451f 100644 --- a/policyengine_uk/tests/policy/baseline/gov/treasury/energy_bills_rebate/council_tax_rebate.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/treasury/energy_bills_rebate/council_tax_rebate.yaml @@ -142,3 +142,325 @@ 2023: ENGLAND output: ebr_council_tax_rebate: 0 + +# Scotland's Cost of Living Award and Wales's Cost of Living Support Scheme +# paid £150 to bands A to D and to Council Tax Reduction recipients in any +# band (Local Government Finance Circular 2/2022, paragraphs 6, 10 and 12; +# Welsh guide, conditions A and B). England's Council Tax Rebate went by band +# alone (billing authority guidance, paragraph 11). Each row below gives the +# band and the year's Council Tax Reduction. +- name: Scotland pays bands A to D, and any band with Council Tax Reduction. + period: 2022 + input: + country: + - SCOTLAND + - SCOTLAND + - SCOTLAND + - SCOTLAND + - SCOTLAND + - SCOTLAND + council_tax_band: + - A + - D + - D + - E + - E + - H + council_tax_reduction: + - 0 + - 0 + - 500 + - 0 + - 500 + - 500 + output: + ebr_council_tax_rebate: + - 150 + - 150 + - 150 + - 0 + - 150 + - 150 + +- name: Wales pays bands A to D, and any band with Council Tax Reduction. + period: 2022 + input: + country: + - WALES + - WALES + - WALES + - WALES + - WALES + - WALES + council_tax_band: + - A + - D + - D + - E + - E + - I + council_tax_reduction: + - 0 + - 0 + - 500 + - 0 + - 500 + - 500 + output: + ebr_council_tax_rebate: + - 150 + - 150 + - 150 + - 0 + - 150 + - 150 + +- name: England pays bands A to D whatever the Council Tax Reduction, and no other band. + period: 2022 + input: + country: + - ENGLAND + - ENGLAND + - ENGLAND + - ENGLAND + - ENGLAND + council_tax_band: + - A + - D + - E + - E + - H + council_tax_reduction: + - 500 + - 500 + - 0 + - 500 + - 500 + output: + ebr_council_tax_rebate: + - 150 + - 150 + - 0 + - 0 + - 0 + +- name: Northern Ireland pays nothing, with or without Council Tax Reduction. + period: 2022 + input: + country: + - NORTHERN_IRELAND + - NORTHERN_IRELAND + - NORTHERN_IRELAND + - NORTHERN_IRELAND + council_tax_band: + - A + - D + - E + - I + council_tax_reduction: + - 500 + - 500 + - 500 + - 0 + output: + ebr_council_tax_rebate: + - 0 + - 0 + - 0 + - 0 + +# Scotland paid "a person in receipt of any amount of CTR" (paragraph 10). +- name: Any amount of Council Tax Reduction qualifies out of band. + period: 2022 + input: + country: + - SCOTLAND + - WALES + council_tax_band: + - F + - F + council_tax_reduction: + - 1 + - 1 + output: + ebr_council_tax_rebate: + - 150 + - 150 + +- name: Scotland and Wales pay out of band only in 2022. + period: 2023 + input: + country: + - SCOTLAND + - WALES + council_tax_band: + - F + - F + council_tax_reduction: + - 500 + - 500 + output: + ebr_council_tax_rebate: + - 0 + - 0 + +- name: Scotland and Wales pay nothing out of band in 2021. + period: 2021 + input: + country: + - SCOTLAND + - WALES + council_tax_band: + - F + - F + council_tax_reduction: + - 500 + - 500 + output: + ebr_council_tax_rebate: + - 0 + - 0 + +# The test reads the same year as the payment, and the household's nation in +# that year. +- name: Council Tax Reduction in another year doesn't qualify a household out of band. + period: 2022 + input: + country: SCOTLAND + council_tax_band: F + council_tax_reduction: + 2021: 500 + 2022: 0 + 2023: 500 + output: + ebr_council_tax_rebate: 0 + +- name: A Scottish household with Council Tax Reduction in 2022 gets the award, though it moves to England in 2023. + period: 2022 + input: + council_tax_band: F + council_tax_reduction: 500 + country: + 2022: SCOTLAND + 2023: ENGLAND + output: + ebr_council_tax_rebate: 150 + +- name: An English household with Council Tax Reduction in 2022 gets nothing out of band, though it moves to Wales in 2023. + period: 2022 + input: + council_tax_band: F + council_tax_reduction: 500 + country: + 2022: ENGLAND + 2023: WALES + output: + ebr_council_tax_rebate: 0 + +# The model works out Council Tax Reduction itself in the cases below. Each +# household has one working-age adult, no income and a band F bill; it claims +# the reduction unless a case says otherwise. +- name: A Scottish band F household's simulated Council Tax Reduction qualifies it. + period: 2022 + input: + people: + adult: + age: 40 + benunits: + unit: + members: [adult] + would_claim_uc: false + would_claim_council_tax_reduction: true + households: + household: + members: [adult] + country: SCOTLAND + council_tax_band: F + council_tax: 2400 + output: + ebr_council_tax_rebate: 150 + energy_bills_rebate: 349 + +- name: A Welsh band F household's simulated Council Tax Reduction qualifies it. + period: 2022 + input: + people: + adult: + age: 40 + benunits: + unit: + members: [adult] + would_claim_uc: false + would_claim_council_tax_reduction: true + households: + household: + members: [adult] + country: WALES + council_tax_band: F + council_tax: 2400 + output: + ebr_council_tax_rebate: 150 + energy_bills_rebate: 349 + +- name: A Scottish band F household that doesn't claim Council Tax Reduction gets nothing. + period: 2022 + input: + people: + adult: + age: 40 + benunits: + unit: + members: [adult] + would_claim_uc: false + would_claim_council_tax_reduction: false + households: + household: + members: [adult] + country: SCOTLAND + council_tax_band: F + council_tax: 2400 + output: + council_tax_reduction: 0 + ebr_council_tax_rebate: 0 + +- name: A Scottish band F household with earnings that end its Council Tax Reduction gets nothing. + period: 2022 + input: + people: + adult: + age: 40 + employment_income: 100_000 + benunits: + unit: + members: [adult] + would_claim_uc: false + would_claim_council_tax_reduction: true + households: + household: + members: [adult] + country: SCOTLAND + council_tax_band: F + council_tax: 2400 + output: + council_tax_reduction: 0 + ebr_council_tax_rebate: 0 + +- name: An English band F household's simulated Council Tax Reduction doesn't qualify it. + period: 2022 + input: + people: + adult: + age: 70 + benunits: + unit: + members: [adult] + would_claim_uc: false + would_claim_council_tax_reduction: true + households: + household: + members: [adult] + country: ENGLAND + council_tax_band: F + council_tax: 2400 + output: + ebr_council_tax_rebate: 0 diff --git a/policyengine_uk/tests/test_energy_bills_rebate_council_tax_reduction_properties.py b/policyengine_uk/tests/test_energy_bills_rebate_council_tax_reduction_properties.py new file mode 100644 index 0000000000..5bba46aaf2 --- /dev/null +++ b/policyengine_uk/tests/test_energy_bills_rebate_council_tax_reduction_properties.py @@ -0,0 +1,202 @@ +"""Property tests for the 2022 £150 and Council Tax Reduction. + +England's Council Tax Rebate went to bands A to D (billing authority guidance, +paragraph 11). Scotland's Cost of Living Award and Wales's Cost of Living +Support Scheme also paid Council Tax Reduction recipients in any band (Local +Government Finance Circular 2/2022, paragraphs 6, 10 and 12; Welsh guide, +conditions A and B). Each nation paid one £150 per dwelling. Northern Ireland +levies domestic rates and had no such payment. + +Invariants, each checked over many generated households: + +1. No household in Northern Ireland is paid, whatever its band or reduction. +2. Every household in Great Britain gets £150 or nothing. +3. Every household in Great Britain in bands A to D gets £150, whatever its + reduction. +4. A household in band E or above gets £150 exactly when it lives in Scotland + or Wales and receives Council Tax Reduction. +5. Nobody is paid in any year but 2022, whatever the reduction. +6. A larger reduction never lowers the payment. +7. Where the model works out the reduction itself, the same rule holds on its + result, and the payment reaches household net income. +""" + +import numpy as np +import pytest +from hypothesis import HealthCheck, given, settings +from hypothesis import strategies as st + +from policyengine_uk import Simulation + +pytestmark = pytest.mark.usefixtures("cloned_uk_tax_benefit_system") + +YEARS = [2021, 2022, 2023] +BANDS = ["A", "B", "C", "D", "E", "F", "G", "H", "I"] +IN_BAND = BANDS[:4] +COUNTRIES = ["ENGLAND", "SCOTLAND", "WALES", "NORTHERN_IRELAND"] +PAYS_RECIPIENTS = ["SCOTLAND", "WALES"] +HOUSEHOLDS = 16 +AMOUNT = 150 + +reductions = st.one_of(st.just(0.0), st.floats(0.01, 5_000, allow_nan=False)) +household = st.tuples(st.sampled_from(BANDS), st.sampled_from(COUNTRIES), reductions) +households = st.lists(household, min_size=HOUSEHOLDS, max_size=HOUSEHOLDS) + + +def each_year(value): + return {year: value for year in YEARS} + + +def people_and_units(count): + return ( + {f"adult_{i}": {"age": each_year(40)} for i in range(count)}, + { + f"unit_{i}": {"members": [f"adult_{i}"], "would_claim_uc": each_year(False)} + for i in range(count) + }, + ) + + +def simulation(drawn): + """One household per drawn case, with its reduction given as an input.""" + bands, countries, amounts = zip(*drawn) + people, benunits = people_and_units(len(drawn)) + return Simulation( + situation={ + "people": people, + "benunits": benunits, + "households": { + f"household_{i}": { + "members": [f"adult_{i}"], + "council_tax_band": each_year(bands[i]), + "country": each_year(countries[i]), + "council_tax_reduction": each_year(amounts[i]), + } + for i in range(len(drawn)) + }, + } + ) + + +def fields(drawn): + bands, countries, amounts = zip(*drawn) + return np.array(bands), np.array(countries), np.array(amounts) + + +SETTINGS = settings( + max_examples=10, + deadline=None, + suppress_health_check=[HealthCheck.too_slow], +) + + +@SETTINGS +@given(households) +def test_northern_ireland_is_never_paid(drawn): + _, countries, _ = fields(drawn) + rebate = simulation(drawn).calculate("ebr_council_tax_rebate", 2022) + np.testing.assert_array_equal(rebate[countries == "NORTHERN_IRELAND"], 0) + + +@SETTINGS +@given(households) +def test_great_britain_pays_at_most_one_150_per_household(drawn): + _, countries, _ = fields(drawn) + rebate = simulation(drawn).calculate("ebr_council_tax_rebate", 2022) + great_britain = rebate[countries != "NORTHERN_IRELAND"] + assert np.isin(great_britain, [0, AMOUNT]).all() + + +@SETTINGS +@given(households) +def test_bands_a_to_d_are_always_paid_in_great_britain(drawn): + bands, countries, _ = fields(drawn) + rebate = simulation(drawn).calculate("ebr_council_tax_rebate", 2022) + in_band = np.isin(bands, IN_BAND) & (countries != "NORTHERN_IRELAND") + np.testing.assert_array_equal(rebate[in_band], AMOUNT) + + +@SETTINGS +@given(households) +def test_higher_bands_are_paid_exactly_for_scottish_and_welsh_recipients(drawn): + bands, countries, amounts = fields(drawn) + rebate = simulation(drawn).calculate("ebr_council_tax_rebate", 2022) + higher_band = ~np.isin(bands, IN_BAND) + expected = np.where(np.isin(countries, PAYS_RECIPIENTS) & (amounts > 0), AMOUNT, 0) + np.testing.assert_array_equal(rebate[higher_band], expected[higher_band]) + + +@SETTINGS +@given(households) +def test_only_2022_is_paid(drawn): + sim = simulation(drawn) + for year in [2021, 2023]: + np.testing.assert_array_equal(sim.calculate("ebr_council_tax_rebate", year), 0) + + +@SETTINGS +@given(households, st.floats(0.01, 5_000, allow_nan=False)) +def test_a_larger_reduction_never_lowers_the_payment(drawn, increase): + bands, countries, amounts = fields(drawn) + larger = [ + (band, country, amount + increase) + for band, country, amount in zip(bands, countries, amounts) + ] + before = simulation(drawn).calculate("ebr_council_tax_rebate", 2022) + after = simulation(larger).calculate("ebr_council_tax_rebate", 2022) + assert (after >= before).all() + + +simulated_household = st.tuples( + st.sampled_from(BANDS), + st.sampled_from(COUNTRIES), + st.integers(0, 40_000), + st.booleans(), +) +simulated_households = st.lists( + simulated_household, min_size=HOUSEHOLDS, max_size=HOUSEHOLDS +) + + +@settings( + max_examples=10, + deadline=None, + suppress_health_check=[HealthCheck.too_slow], +) +@given(simulated_households) +def test_the_rule_holds_on_a_simulated_reduction(drawn): + bands, countries, earnings, claims = zip(*drawn) + bands, countries = np.array(bands), np.array(countries) + people, benunits = people_and_units(len(drawn)) + for i in range(len(drawn)): + people[f"adult_{i}"]["employment_income"] = each_year(earnings[i]) + benunits[f"unit_{i}"]["would_claim_council_tax_reduction"] = each_year( + claims[i] + ) + sim = Simulation( + situation={ + "people": people, + "benunits": benunits, + "households": { + f"household_{i}": { + "members": [f"adult_{i}"], + "council_tax_band": each_year(bands[i]), + "country": each_year(countries[i]), + "council_tax": each_year(2_400), + } + for i in range(len(drawn)) + }, + } + ) + rebate = sim.calculate("ebr_council_tax_rebate", 2022) + receives = sim.calculate("council_tax_reduction", 2022) > 0 + in_band = np.isin(bands, IN_BAND) + expected = np.where( + countries == "NORTHERN_IRELAND", + 0, + np.where(in_band | (np.isin(countries, PAYS_RECIPIENTS) & receives), AMOUNT, 0), + ) + np.testing.assert_array_equal(rebate, expected) + # The payment reaches net income without a circular dependency. + assert np.isfinite(sim.calculate("household_net_income", 2022)).all() + assert (sim.calculate("energy_bills_rebate", 2022) >= rebate).all() diff --git a/policyengine_uk/variables/gov/treasury/energy_bills_rebate/council_tax_rebate.py b/policyengine_uk/variables/gov/treasury/energy_bills_rebate/council_tax_rebate.py index cf1fc88144..444fc378a8 100644 --- a/policyengine_uk/variables/gov/treasury/energy_bills_rebate/council_tax_rebate.py +++ b/policyengine_uk/variables/gov/treasury/energy_bills_rebate/council_tax_rebate.py @@ -18,9 +18,9 @@ class ebr_council_tax_rebate(Variable): "for the disabled band reduction, so it doesn't pay band E homes " "charged at band D (England's paragraph 11(i), Scotland's paragraph " "12, Wales's condition B) unless they qualify through Council Tax " - "Reduction. It also leaves out Scotland's payments to exempt dwellings " - "(paragraphs 16 to 18), and second adult rebate, which it doesn't " - "simulate." + "Reduction. It has no council tax exemption input, so it can't apply " + "Scotland's rules for exempt dwellings (paragraphs 15 to 18), and it " + "doesn't simulate second adult rebate." ) entity = Household definition_period = YEAR From ea48d710caab21e5f78b9fd02af755850493224e Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sat, 31 Oct 2026 09:26:44 -0400 Subject: [PATCH 3/5] Correct the rebate's documented gaps and test each route Say which nations pay band E homes on the disabled band reduction, name Scotland's Council Tax Reduction for bands E to H as a gap, name councils as the actors, and add the Scottish and Welsh sources to the docs page. Assert the simulated reductions in the YAML cases and test reductions in other years. Co-Authored-By: Claude Opus 5.5 --- changelog.d/2766.fixed.md | 2 +- .../gov/treasury/cost-of-living-payments.md | 33 ++++++++------ .../council_tax_reduction_countries.yaml | 2 +- policyengine_uk/programs.yaml | 11 +++-- .../council_tax_rebate.yaml | 39 +++++++++------- ...rebate_council_tax_reduction_properties.py | 45 +++++++++++++------ .../energy_bills_rebate/council_tax_rebate.py | 43 ++++++++++-------- 7 files changed, 107 insertions(+), 68 deletions(-) diff --git a/changelog.d/2766.fixed.md b/changelog.d/2766.fixed.md index 25b804cc61..9daf74853a 100644 --- a/changelog.d/2766.fixed.md +++ b/changelog.d/2766.fixed.md @@ -1 +1 @@ -Pay the 2022 £150 to Council Tax Reduction recipients in any council tax band in Scotland and Wales, as Scotland's Cost of Living Award and Wales's Cost of Living Support Scheme did. +Pay the 2022 £150 to Council Tax Reduction recipients in any council tax band in Scotland and Wales, as Scottish and Welsh councils did. diff --git a/docs/book/programs/gov/treasury/cost-of-living-payments.md b/docs/book/programs/gov/treasury/cost-of-living-payments.md index 3affeda8d3..ebec552ddc 100644 --- a/docs/book/programs/gov/treasury/cost-of-living-payments.md +++ b/docs/book/programs/gov/treasury/cost-of-living-payments.md @@ -16,17 +16,21 @@ spike in domestic energy prices. Two strands: England, a one-off in 2022-23. Households qualified on their band on 1 April 2022. The guidance asked billing authorities to pay from April and set 30 September 2022 as the deadline for the payments the government - would reconcile (paragraph 7). Scotland and Wales paid their own £150 - awards to bands A–D and to Council Tax Reduction recipients in any band; - the model tests `council_tax_reduction` for the year, not receipt on 14 - February 2022 (Scotland) or 15 February 2022 (Wales). All three nations - also paid band E homes charged at band D under the disabled band - reduction. The model has no input for that reduction, so it pays those - homes only if they qualify through Council Tax Reduction. Northern - Ireland levies domestic rates, - not council tax, and had no Council Tax Rebate, so the model pays none - there whatever the household's council tax band (the enhanced FRS gives - every Northern Ireland household band A, the default policyengine-uk-data + would reconcile (paragraph 7). Scottish councils paid the Cost of Living + Award and Welsh councils the Cost of Living Support Scheme, £150 each, to + bands A–D and to Council Tax Reduction recipients in any band. Scottish + councils tested receipt on 14 February 2022 and Welsh councils on 15 + February 2022. The model reads `council_tax_reduction` for the whole year. + Councils in all three nations also paid band E homes charged at band D + under the disabled band reduction. The model has no input for that + reduction. In Scotland and Wales it pays those homes only when they also + receive Council Tax Reduction; in England it never pays them. The model + doesn't simulate Scotland's separate Council Tax Reduction for bands E to + H (regulation 14A, inserted by SSI 2016/253), so a Scottish household on + that alone misses the payment. Northern Ireland levies domestic rates, not + council tax, and had no Council Tax Rebate, so the model pays none there + whatever the household's council tax band (the enhanced FRS gives every + Northern Ireland household band A, the default policyengine-uk-data assigns when the FRS records no band). - **Energy Bills Support Scheme**, a £400 discount on domestic electricity bills in Great Britain, paid in six monthly instalments from October 2022 @@ -54,8 +58,8 @@ PolicyEngine models these via: reforms - `council_tax_rebate/bands.yaml` — qualifying CT bands (A–D) - `council_tax_rebate/council_tax_reduction_countries.yaml` — countries - that also paid Council Tax Reduction recipients in any band (Scotland - and Wales) + whose councils also paid Council Tax Reduction recipients in any band + (Scotland and Wales) - `council_tax_rebate/amount.yaml` — £150 in 2022-23 and nothing in any other year @@ -151,5 +155,8 @@ will collect all three payments. This matches the actual policy. - [HMT/DWP, May 2022 cost-of-living support package announcement](https://www.gov.uk/government/news/millions-of-most-vulnerable-households-will-receive-1200-of-help-with-cost-of-living) - DWP, [Cost-of-Living Payments 2023-24 guidance](https://www.gov.uk/guidance/cost-of-living-payments-2023-to-2024) (means-tested, pensioner and disability strands). - HMT, [Energy Bills Support Scheme](https://www.gov.uk/government/publications/the-energy-bills-support-scheme-explainer) and [Council Tax Energy Rebate](https://www.gov.uk/government/publications/the-council-tax-rebate-2022-23-billing-authority-guidance). +- Scottish Government, [Local Government Finance Circular 2/2022](https://www.gov.scot/publications/local-government-finance-circular-2-2022-guidance-to-local-authorities-april-2022-cost-of-living-award/) (Cost of Living Award). +- Welsh Government, [Cost of Living Support Scheme guide for local authorities](https://www.gov.wales/cost-living-support-scheme-guide-local-authorities-html). +- [The Council Tax Reduction (Scotland) Amendment (No. 2) Regulations 2016](https://www.legislation.gov.uk/ssi/2016/253/made) (Council Tax Reduction for bands E to H). - DWP, [HBAI quality and methodology information report, FYE 2023](https://www.gov.uk/government/statistics/households-below-average-income-for-financial-years-ending-1995-to-2023/households-below-average-income-series-quality-and-methodology-information-report-fye-2023) (treatment of the cost-of-living support schemes in HBAI income). - House of Commons Library briefing [CBP-9501 — Cost of Living Payments and the energy crisis](https://commonslibrary.parliament.uk/research-briefings/cbp-9501/). diff --git a/policyengine_uk/parameters/gov/treasury/energy_bills_rebate/council_tax_rebate/council_tax_reduction_countries.yaml b/policyengine_uk/parameters/gov/treasury/energy_bills_rebate/council_tax_rebate/council_tax_reduction_countries.yaml index 2308f69859..2900137583 100644 --- a/policyengine_uk/parameters/gov/treasury/energy_bills_rebate/council_tax_rebate/council_tax_reduction_countries.yaml +++ b/policyengine_uk/parameters/gov/treasury/energy_bills_rebate/council_tax_rebate/council_tax_reduction_countries.yaml @@ -1,4 +1,4 @@ -description: Countries that paid the 2022 £150 to Council Tax Reduction recipients in any council tax band. Scotland's Cost of Living Award and Wales's Cost of Living Support Scheme paid them, while England's Council Tax Rebate went by band alone. +description: Countries whose councils paid the 2022 £150 to Council Tax Reduction recipients in any council tax band. Scottish councils paid the Cost of Living Award and Welsh councils the Cost of Living Support Scheme to them, while English billing authorities paid by band alone. values: 0001-01-01: value: diff --git a/policyengine_uk/programs.yaml b/policyengine_uk/programs.yaml index d310a5d02e..c6343f6006 100644 --- a/policyengine_uk/programs.yaml +++ b/policyengine_uk/programs.yaml @@ -617,10 +617,13 @@ programs: D in Great Britain and for Council Tax Reduction recipients in any band in Scotland and Wales (none in Northern Ireland, which has domestic rates), the £400 Energy Bills Support Scheme, and Northern Ireland's - £200 Alternative Fuel Payment. Leaves out band E homes charged at band D - under the disabled band reduction, Scotland's rules for exempt - dwellings, England's discretionary fund, Great Britain's Alternative - Fuel Payment and the alternative funding schemes. + £200 Alternative Fuel Payment. Has no input for the disabled band + reduction, so it pays band E homes charged at band D only when they also + receive Council Tax Reduction in Scotland and Wales, and never in + England. Leaves out Scotland's Council Tax Reduction for bands E to H, + Scotland's rules for exempt dwellings, England's discretionary fund, + Great Britain's Alternative Fuel Payment and the alternative funding + schemes. - id: household_energy_payment name: Household Energy Payment diff --git a/policyengine_uk/tests/policy/baseline/gov/treasury/energy_bills_rebate/council_tax_rebate.yaml b/policyengine_uk/tests/policy/baseline/gov/treasury/energy_bills_rebate/council_tax_rebate.yaml index 7bf84b451f..1bad0a23b3 100644 --- a/policyengine_uk/tests/policy/baseline/gov/treasury/energy_bills_rebate/council_tax_rebate.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/treasury/energy_bills_rebate/council_tax_rebate.yaml @@ -143,13 +143,13 @@ output: ebr_council_tax_rebate: 0 -# Scotland's Cost of Living Award and Wales's Cost of Living Support Scheme -# paid £150 to bands A to D and to Council Tax Reduction recipients in any -# band (Local Government Finance Circular 2/2022, paragraphs 6, 10 and 12; -# Welsh guide, conditions A and B). England's Council Tax Rebate went by band -# alone (billing authority guidance, paragraph 11). Each row below gives the -# band and the year's Council Tax Reduction. -- name: Scotland pays bands A to D, and any band with Council Tax Reduction. +# Scottish councils paid the Cost of Living Award and Welsh councils the Cost +# of Living Support Scheme, £150 each, to bands A to D and to Council Tax +# Reduction recipients in any band (Local Government Finance Circular 2/2022, +# paragraphs 6, 10 and 12; Welsh guide, conditions A and B). English billing +# authorities paid by band alone (billing authority guidance, paragraph 11). +# Each row below gives the band and the year's Council Tax Reduction. +- name: The model pays Scottish bands A to D, and any band with Council Tax Reduction. period: 2022 input: country: @@ -182,7 +182,7 @@ - 150 - 150 -- name: Wales pays bands A to D, and any band with Council Tax Reduction. +- name: The model pays Welsh bands A to D, and any band with Council Tax Reduction. period: 2022 input: country: @@ -215,7 +215,7 @@ - 150 - 150 -- name: England pays bands A to D whatever the Council Tax Reduction, and no other band. +- name: The model pays English bands A to D whatever the Council Tax Reduction, and no other band. period: 2022 input: country: @@ -244,7 +244,7 @@ - 0 - 0 -- name: Northern Ireland pays nothing, with or without Council Tax Reduction. +- name: The model pays nothing in Northern Ireland, with or without Council Tax Reduction. period: 2022 input: country: @@ -269,7 +269,8 @@ - 0 - 0 -# Scotland paid "a person in receipt of any amount of CTR" (paragraph 10). +# Scottish councils paid "a person in receipt of any amount of CTR" (paragraph +# 10). - name: Any amount of Council Tax Reduction qualifies out of band. period: 2022 input: @@ -287,7 +288,7 @@ - 150 - 150 -- name: Scotland and Wales pay out of band only in 2022. +- name: The model pays Scotland and Wales out of band only in 2022. period: 2023 input: country: @@ -304,7 +305,7 @@ - 0 - 0 -- name: Scotland and Wales pay nothing out of band in 2021. +- name: The model pays Scotland and Wales nothing out of band in 2021. period: 2021 input: country: @@ -321,8 +322,8 @@ - 0 - 0 -# The test reads the same year as the payment, and the household's nation in -# that year. +# The model reads the reduction in the payment's year, and the household's +# nation in that year. - name: Council Tax Reduction in another year doesn't qualify a household out of band. period: 2022 input: @@ -358,8 +359,9 @@ ebr_council_tax_rebate: 0 # The model works out Council Tax Reduction itself in the cases below. Each -# household has one working-age adult, no income and a band F bill; it claims -# the reduction unless a case says otherwise. +# household has one adult, no income and a band F bill; it claims the +# reduction unless a case says otherwise. The English case uses a pensioner, +# because the model simulates England's pension-age scheme for every council. - name: A Scottish band F household's simulated Council Tax Reduction qualifies it. period: 2022 input: @@ -378,6 +380,7 @@ council_tax_band: F council_tax: 2400 output: + council_tax_reduction: 2400 ebr_council_tax_rebate: 150 energy_bills_rebate: 349 @@ -399,6 +402,7 @@ council_tax_band: F council_tax: 2400 output: + council_tax_reduction: 2400 ebr_council_tax_rebate: 150 energy_bills_rebate: 349 @@ -463,4 +467,5 @@ council_tax_band: F council_tax: 2400 output: + council_tax_reduction: 2400 ebr_council_tax_rebate: 0 diff --git a/policyengine_uk/tests/test_energy_bills_rebate_council_tax_reduction_properties.py b/policyengine_uk/tests/test_energy_bills_rebate_council_tax_reduction_properties.py index 5bba46aaf2..18f36c9112 100644 --- a/policyengine_uk/tests/test_energy_bills_rebate_council_tax_reduction_properties.py +++ b/policyengine_uk/tests/test_energy_bills_rebate_council_tax_reduction_properties.py @@ -1,23 +1,26 @@ """Property tests for the 2022 £150 and Council Tax Reduction. -England's Council Tax Rebate went to bands A to D (billing authority guidance, -paragraph 11). Scotland's Cost of Living Award and Wales's Cost of Living -Support Scheme also paid Council Tax Reduction recipients in any band (Local -Government Finance Circular 2/2022, paragraphs 6, 10 and 12; Welsh guide, -conditions A and B). Each nation paid one £150 per dwelling. Northern Ireland -levies domestic rates and had no such payment. +English billing authorities paid the Council Tax Rebate to bands A to D +(billing authority guidance, paragraph 11). Scottish councils paid the Cost of +Living Award and Welsh councils the Cost of Living Support Scheme to those +bands and to Council Tax Reduction recipients in any band (Local Government +Finance Circular 2/2022, paragraphs 6, 10 and 12; Welsh guide, conditions A and +B). Councils in each nation paid one £150 per dwelling. Northern Ireland levies +domestic rates and had no such payment. Invariants, each checked over many generated households: -1. No household in Northern Ireland is paid, whatever its band or reduction. +1. The model pays no household in Northern Ireland, whatever its band or + reduction. 2. Every household in Great Britain gets £150 or nothing. 3. Every household in Great Britain in bands A to D gets £150, whatever its reduction. 4. A household in band E or above gets £150 exactly when it lives in Scotland or Wales and receives Council Tax Reduction. -5. Nobody is paid in any year but 2022, whatever the reduction. -6. A larger reduction never lowers the payment. -7. Where the model works out the reduction itself, the same rule holds on its +5. The model pays nobody in any year but 2022, whatever the reduction. +6. A reduction in another year never qualifies a household out of band. +7. A larger reduction never lowers the payment. +8. Where the model works out the reduction itself, the same rule holds on its result, and the payment reaches household net income. """ @@ -38,7 +41,11 @@ HOUSEHOLDS = 16 AMOUNT = 150 -reductions = st.one_of(st.just(0.0), st.floats(0.01, 5_000, allow_nan=False)) +reductions = st.one_of( + st.just(0.0), + st.sampled_from([0.01, 1.0]), + st.floats(0.01, 5_000, allow_nan=False), +) household = st.tuples(st.sampled_from(BANDS), st.sampled_from(COUNTRIES), reductions) households = st.lists(household, min_size=HOUSEHOLDS, max_size=HOUSEHOLDS) @@ -57,7 +64,7 @@ def people_and_units(count): ) -def simulation(drawn): +def simulation(drawn, reduction_years=YEARS): """One household per drawn case, with its reduction given as an input.""" bands, countries, amounts = zip(*drawn) people, benunits = people_and_units(len(drawn)) @@ -70,7 +77,10 @@ def simulation(drawn): "members": [f"adult_{i}"], "council_tax_band": each_year(bands[i]), "country": each_year(countries[i]), - "council_tax_reduction": each_year(amounts[i]), + "council_tax_reduction": { + year: amounts[i] if year in reduction_years else 0.0 + for year in YEARS + }, } for i in range(len(drawn)) }, @@ -134,6 +144,15 @@ def test_only_2022_is_paid(drawn): np.testing.assert_array_equal(sim.calculate("ebr_council_tax_rebate", year), 0) +@SETTINGS +@given(households) +def test_a_reduction_in_another_year_does_not_qualify(drawn): + bands, _, _ = fields(drawn) + sim = simulation(drawn, reduction_years=[2021, 2023]) + rebate = sim.calculate("ebr_council_tax_rebate", 2022) + np.testing.assert_array_equal(rebate[~np.isin(bands, IN_BAND)], 0) + + @SETTINGS @given(households, st.floats(0.01, 5_000, allow_nan=False)) def test_a_larger_reduction_never_lowers_the_payment(drawn, increase): diff --git a/policyengine_uk/variables/gov/treasury/energy_bills_rebate/council_tax_rebate.py b/policyengine_uk/variables/gov/treasury/energy_bills_rebate/council_tax_rebate.py index 444fc378a8..a602adac76 100644 --- a/policyengine_uk/variables/gov/treasury/energy_bills_rebate/council_tax_rebate.py +++ b/policyengine_uk/variables/gov/treasury/energy_bills_rebate/council_tax_rebate.py @@ -4,23 +4,28 @@ class ebr_council_tax_rebate(Variable): label = "Council Tax Rebate (EBR)" documentation = ( - "Council Tax discount under the Energy Bills Rebate. England's £150 " - "Council Tax Rebate went to households in bands A to D (billing " - "authority guidance, paragraphs 2 and 11). Scotland's Cost of Living " - "Award and Wales's Cost of Living Support Scheme paid £150 to bands A " - "to D and to Council Tax Reduction recipients in any band (Local " - "Government Finance Circular 2/2022, paragraphs 6, 10 and 12; Welsh " - "guide, conditions A and B). Northern Ireland levies domestic rates, " - "not council tax, and had no Council Tax Rebate; its households " - "received the £600 Energy Bills Support Scheme payment. The test " - "reads council_tax_reduction for the year, not receipt on 14 February " - "2022 (Scotland) or 15 February 2022 (Wales). The model has no input " - "for the disabled band reduction, so it doesn't pay band E homes " - "charged at band D (England's paragraph 11(i), Scotland's paragraph " - "12, Wales's condition B) unless they qualify through Council Tax " - "Reduction. It has no council tax exemption input, so it can't apply " - "Scotland's rules for exempt dwellings (paragraphs 15 to 18), and it " - "doesn't simulate second adult rebate." + "Council Tax discount under the Energy Bills Rebate. English billing " + "authorities paid the £150 Council Tax Rebate to households in bands A " + "to D (billing authority guidance, paragraphs 2 and 11). Scottish " + "councils paid the Cost of Living Award and Welsh councils the Cost of " + "Living Support Scheme, £150 each, to bands A to D and to Council Tax " + "Reduction recipients in any band (Local Government Finance Circular " + "2/2022, paragraphs 6, 10 and 12; Welsh guide, conditions A and B). " + "Northern Ireland levies domestic rates, not council tax, and had no " + "Council Tax Rebate; its households received the £600 Energy Bills " + "Support Scheme payment. Scottish councils tested receipt on 14 " + "February 2022 and Welsh councils on 15 February 2022. The model reads " + "council_tax_reduction for the whole year. The model has no input for " + "the disabled band reduction, which qualified band E homes charged at " + "band D (England's paragraph 11(i), Scotland's paragraph 12, Wales's " + "condition B). In Scotland and Wales it pays those homes only when " + "they also receive Council Tax Reduction; in England it never pays " + "them. It has no council tax exemption input, so it can't apply " + "Scotland's rules for exempt dwellings (paragraphs 15 to 18). It " + "doesn't simulate second adult rebate or Scotland's separate Council " + "Tax Reduction for bands E to H (regulation 14A, inserted by SSI " + "2016/253), so a Scottish household on either alone misses the " + "payment." ) entity = Household definition_period = YEAR @@ -41,8 +46,8 @@ def formula(household, period, parameters): np.array([ct_band == getattr(ct_band_values, band) for band in p.bands]), axis=0, ) - # Scotland and Wales also paid Council Tax Reduction recipients in any - # band; England went by band alone. + # Scottish and Welsh councils also paid Council Tax Reduction recipients + # in any band; English billing authorities paid by band alone. country = household("country", period) pays_reduction_recipients = np.isin( country.decode_to_str(), list(p.council_tax_reduction_countries) From 00c70fd0fed8fe295b60e20ed4aec42fb30cf26d Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sat, 31 Oct 2026 09:48:12 -0400 Subject: [PATCH 4/5] Test that the rebate reaches net income in full Compare net income with the rebate on and zeroed, limit the second adult rebate caveat to bands E and above, and give the program notes and test comments a subject that acts. Co-Authored-By: Claude Opus 5.5 --- policyengine_uk/programs.yaml | 22 ++++---- .../council_tax_rebate.yaml | 8 +-- ...rebate_council_tax_reduction_properties.py | 51 +++++++++++-------- .../energy_bills_rebate/council_tax_rebate.py | 22 ++++---- 4 files changed, 56 insertions(+), 47 deletions(-) diff --git a/policyengine_uk/programs.yaml b/policyengine_uk/programs.yaml index c6343f6006..c4ae5c574d 100644 --- a/policyengine_uk/programs.yaml +++ b/policyengine_uk/programs.yaml @@ -613,17 +613,17 @@ programs: verified_start_year: 2022 verified_end_year: 2023 notes: >- - Temporary program, ended 2023. The £150 Council Tax Rebate in bands A to - D in Great Britain and for Council Tax Reduction recipients in any band - in Scotland and Wales (none in Northern Ireland, which has domestic - rates), the £400 Energy Bills Support Scheme, and Northern Ireland's - £200 Alternative Fuel Payment. Has no input for the disabled band - reduction, so it pays band E homes charged at band D only when they also - receive Council Tax Reduction in Scotland and Wales, and never in - England. Leaves out Scotland's Council Tax Reduction for bands E to H, - Scotland's rules for exempt dwellings, England's discretionary fund, - Great Britain's Alternative Fuel Payment and the alternative funding - schemes. + Temporary program, ended 2023. The model pays the £150 Council Tax Rebate + in bands A to D in Great Britain and to Council Tax Reduction recipients + in any band in Scotland and Wales (none in Northern Ireland, which has + domestic rates), the £400 Energy Bills Support Scheme, and Northern + Ireland's £200 Alternative Fuel Payment. It has no input for the + disabled band reduction, so it pays band E homes charged at band D only + when they also receive Council Tax Reduction in Scotland and Wales, and + never in England. It leaves out Scotland's Council Tax Reduction for + bands E to H, Scotland's rules for exempt dwellings, England's + discretionary fund, Great Britain's Alternative Fuel Payment and the + alternative funding schemes. - id: household_energy_payment name: Household Energy Payment diff --git a/policyengine_uk/tests/policy/baseline/gov/treasury/energy_bills_rebate/council_tax_rebate.yaml b/policyengine_uk/tests/policy/baseline/gov/treasury/energy_bills_rebate/council_tax_rebate.yaml index 1bad0a23b3..9126ae7994 100644 --- a/policyengine_uk/tests/policy/baseline/gov/treasury/energy_bills_rebate/council_tax_rebate.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/treasury/energy_bills_rebate/council_tax_rebate.yaml @@ -148,7 +148,6 @@ # Reduction recipients in any band (Local Government Finance Circular 2/2022, # paragraphs 6, 10 and 12; Welsh guide, conditions A and B). English billing # authorities paid by band alone (billing authority guidance, paragraph 11). -# Each row below gives the band and the year's Council Tax Reduction. - name: The model pays Scottish bands A to D, and any band with Council Tax Reduction. period: 2022 input: @@ -359,9 +358,10 @@ ebr_council_tax_rebate: 0 # The model works out Council Tax Reduction itself in the cases below. Each -# household has one adult, no income and a band F bill; it claims the -# reduction unless a case says otherwise. The English case uses a pensioner, -# because the model simulates England's pension-age scheme for every council. +# household has one adult and a band F bill. The adult has no income and +# claims the reduction unless a case says otherwise. The English case uses a +# pensioner, because the model simulates England's pension-age scheme for +# every council. - name: A Scottish band F household's simulated Council Tax Reduction qualifies it. period: 2022 input: diff --git a/policyengine_uk/tests/test_energy_bills_rebate_council_tax_reduction_properties.py b/policyengine_uk/tests/test_energy_bills_rebate_council_tax_reduction_properties.py index 18f36c9112..9a333d7ccf 100644 --- a/policyengine_uk/tests/test_energy_bills_rebate_council_tax_reduction_properties.py +++ b/policyengine_uk/tests/test_energy_bills_rebate_council_tax_reduction_properties.py @@ -8,7 +8,7 @@ B). Councils in each nation paid one £150 per dwelling. Northern Ireland levies domestic rates and had no such payment. -Invariants, each checked over many generated households: +Hypothesis generates households and checks these invariants: 1. The model pays no household in Northern Ireland, whatever its band or reduction. @@ -21,7 +21,7 @@ 6. A reduction in another year never qualifies a household out of band. 7. A larger reduction never lowers the payment. 8. Where the model works out the reduction itself, the same rule holds on its - result, and the payment reaches household net income. + result, and the payment raises household net income by its full amount. """ import numpy as np @@ -65,7 +65,7 @@ def people_and_units(count): def simulation(drawn, reduction_years=YEARS): - """One household per drawn case, with its reduction given as an input.""" + """Build one household per drawn case and supply its reduction as an input.""" bands, countries, amounts = zip(*drawn) people, benunits = people_and_units(len(drawn)) return Simulation( @@ -192,21 +192,26 @@ def test_the_rule_holds_on_a_simulated_reduction(drawn): benunits[f"unit_{i}"]["would_claim_council_tax_reduction"] = each_year( claims[i] ) - sim = Simulation( - situation={ - "people": people, - "benunits": benunits, - "households": { - f"household_{i}": { - "members": [f"adult_{i}"], - "council_tax_band": each_year(bands[i]), - "country": each_year(countries[i]), - "council_tax": each_year(2_400), - } - for i in range(len(drawn)) - }, - } - ) + + def household_simulation(**inputs): + return Simulation( + situation={ + "people": people, + "benunits": benunits, + "households": { + f"household_{i}": { + "members": [f"adult_{i}"], + "council_tax_band": each_year(bands[i]), + "country": each_year(countries[i]), + "council_tax": each_year(2_400), + **inputs, + } + for i in range(len(drawn)) + }, + } + ) + + sim = household_simulation() rebate = sim.calculate("ebr_council_tax_rebate", 2022) receives = sim.calculate("council_tax_reduction", 2022) > 0 in_band = np.isin(bands, IN_BAND) @@ -216,6 +221,10 @@ def test_the_rule_holds_on_a_simulated_reduction(drawn): np.where(in_band | (np.isin(countries, PAYS_RECIPIENTS) & receives), AMOUNT, 0), ) np.testing.assert_array_equal(rebate, expected) - # The payment reaches net income without a circular dependency. - assert np.isfinite(sim.calculate("household_net_income", 2022)).all() - assert (sim.calculate("energy_bills_rebate", 2022) >= rebate).all() + # The payment raises net income by its full amount, with no circular + # dependency between the rebate and the income it feeds. + without_rebate = household_simulation(ebr_council_tax_rebate=each_year(0)) + gain = sim.calculate("household_net_income", 2022) - without_rebate.calculate( + "household_net_income", 2022 + ) + np.testing.assert_allclose(gain, rebate, atol=0.01) diff --git a/policyengine_uk/variables/gov/treasury/energy_bills_rebate/council_tax_rebate.py b/policyengine_uk/variables/gov/treasury/energy_bills_rebate/council_tax_rebate.py index a602adac76..8e97803d2d 100644 --- a/policyengine_uk/variables/gov/treasury/energy_bills_rebate/council_tax_rebate.py +++ b/policyengine_uk/variables/gov/treasury/energy_bills_rebate/council_tax_rebate.py @@ -15,17 +15,17 @@ class ebr_council_tax_rebate(Variable): "Council Tax Rebate; its households received the £600 Energy Bills " "Support Scheme payment. Scottish councils tested receipt on 14 " "February 2022 and Welsh councils on 15 February 2022. The model reads " - "council_tax_reduction for the whole year. The model has no input for " - "the disabled band reduction, which qualified band E homes charged at " - "band D (England's paragraph 11(i), Scotland's paragraph 12, Wales's " - "condition B). In Scotland and Wales it pays those homes only when " - "they also receive Council Tax Reduction; in England it never pays " - "them. It has no council tax exemption input, so it can't apply " - "Scotland's rules for exempt dwellings (paragraphs 15 to 18). It " - "doesn't simulate second adult rebate or Scotland's separate Council " - "Tax Reduction for bands E to H (regulation 14A, inserted by SSI " - "2016/253), so a Scottish household on either alone misses the " - "payment." + "council_tax_reduction for the whole year. Councils in all three " + "nations also paid band E homes charged at band D under the disabled " + "band reduction (England's paragraph 11(i), Scotland's paragraph 12, " + "Wales's condition B). The model has no input for that reduction. In " + "Scotland and Wales it pays those homes only when they also receive " + "Council Tax Reduction; in England it never pays them. It has no " + "council tax exemption input, so it can't apply Scotland's rules for " + "exempt dwellings (paragraphs 15 to 18). It doesn't simulate second " + "adult rebate or Scotland's separate Council Tax Reduction for bands E " + "to H (regulation 14A, inserted by SSI 2016/253), so a Scottish " + "household in band E or above on either alone misses the payment." ) entity = Household definition_period = YEAR From fe1c4f1abdf941b0dbafaaf34bf63987f8e56372 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sat, 31 Oct 2026 10:02:57 -0400 Subject: [PATCH 5/5] Name the councils in the rebate's documentation Co-Authored-By: Claude Opus 5.5 --- .../gov/treasury/cost-of-living-payments.md | 8 ++++---- policyengine_uk/programs.yaml | 12 +++++------ .../energy_bills_rebate/council_tax_rebate.py | 20 +++++++++---------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/book/programs/gov/treasury/cost-of-living-payments.md b/docs/book/programs/gov/treasury/cost-of-living-payments.md index ebec552ddc..7e543d6f98 100644 --- a/docs/book/programs/gov/treasury/cost-of-living-payments.md +++ b/docs/book/programs/gov/treasury/cost-of-living-payments.md @@ -21,13 +21,13 @@ spike in domestic energy prices. Two strands: bands A–D and to Council Tax Reduction recipients in any band. Scottish councils tested receipt on 14 February 2022 and Welsh councils on 15 February 2022. The model reads `council_tax_reduction` for the whole year. - Councils in all three nations also paid band E homes charged at band D - under the disabled band reduction. The model has no input for that + Councils in all three nations also paid band E homes they charged at band + D under the disabled band reduction. The model has no input for that reduction. In Scotland and Wales it pays those homes only when they also receive Council Tax Reduction; in England it never pays them. The model doesn't simulate Scotland's separate Council Tax Reduction for bands E to - H (regulation 14A, inserted by SSI 2016/253), so a Scottish household on - that alone misses the payment. Northern Ireland levies domestic rates, not + H (regulation 14A; SSI 2016/253), so a Scottish household on that alone + misses the payment. Northern Ireland levies domestic rates, not council tax, and had no Council Tax Rebate, so the model pays none there whatever the household's council tax band (the enhanced FRS gives every Northern Ireland household band A, the default policyengine-uk-data diff --git a/policyengine_uk/programs.yaml b/policyengine_uk/programs.yaml index c4ae5c574d..db3a7b58d3 100644 --- a/policyengine_uk/programs.yaml +++ b/policyengine_uk/programs.yaml @@ -618,12 +618,12 @@ programs: in any band in Scotland and Wales (none in Northern Ireland, which has domestic rates), the £400 Energy Bills Support Scheme, and Northern Ireland's £200 Alternative Fuel Payment. It has no input for the - disabled band reduction, so it pays band E homes charged at band D only - when they also receive Council Tax Reduction in Scotland and Wales, and - never in England. It leaves out Scotland's Council Tax Reduction for - bands E to H, Scotland's rules for exempt dwellings, England's - discretionary fund, Great Britain's Alternative Fuel Payment and the - alternative funding schemes. + disabled band reduction, so it pays band E homes that councils charged + at band D only when they also receive Council Tax Reduction in Scotland + and Wales, and never in England. It leaves out Scotland's Council Tax + Reduction for bands E to H, Scotland's rules for exempt dwellings, + England's discretionary fund, Great Britain's Alternative Fuel Payment + and the alternative funding schemes. - id: household_energy_payment name: Household Energy Payment diff --git a/policyengine_uk/variables/gov/treasury/energy_bills_rebate/council_tax_rebate.py b/policyengine_uk/variables/gov/treasury/energy_bills_rebate/council_tax_rebate.py index 8e97803d2d..9fd6637929 100644 --- a/policyengine_uk/variables/gov/treasury/energy_bills_rebate/council_tax_rebate.py +++ b/policyengine_uk/variables/gov/treasury/energy_bills_rebate/council_tax_rebate.py @@ -16,16 +16,16 @@ class ebr_council_tax_rebate(Variable): "Support Scheme payment. Scottish councils tested receipt on 14 " "February 2022 and Welsh councils on 15 February 2022. The model reads " "council_tax_reduction for the whole year. Councils in all three " - "nations also paid band E homes charged at band D under the disabled " - "band reduction (England's paragraph 11(i), Scotland's paragraph 12, " - "Wales's condition B). The model has no input for that reduction. In " - "Scotland and Wales it pays those homes only when they also receive " - "Council Tax Reduction; in England it never pays them. It has no " - "council tax exemption input, so it can't apply Scotland's rules for " - "exempt dwellings (paragraphs 15 to 18). It doesn't simulate second " - "adult rebate or Scotland's separate Council Tax Reduction for bands E " - "to H (regulation 14A, inserted by SSI 2016/253), so a Scottish " - "household in band E or above on either alone misses the payment." + "nations also paid band E homes they charged at band D under the " + "disabled band reduction (England's paragraph 11(i), Scotland's " + "paragraph 12, Wales's condition B). The model has no input for that " + "reduction. In Scotland and Wales it pays those homes only when they " + "also receive Council Tax Reduction; in England it never pays them. It " + "has no council tax exemption input, so it can't apply Scotland's " + "rules for exempt dwellings (paragraphs 15 to 18). It doesn't simulate " + "second adult rebate or Scotland's separate Council Tax Reduction for " + "bands E to H (regulation 14A; SSI 2016/253), so a Scottish household " + "in band E or above on either alone misses the payment." ) entity = Household definition_period = YEAR