From 0aa0de3b01ed62dfd06f66bcb1d9a7f098f16436 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Wed, 30 Sep 2026 11:56:15 -0400 Subject: [PATCH 1/4] Date the mixed-age couple Pension Credit exclusion and model the SI 2019/37 saving is_pension_credit_eligible required every adult to be over State Pension age in every year, so PolicyEngine applied SPCA 2002 s.4(1A) before its 15 May 2019 commencement (SI 2019/37 art. 3) and ignored the art. 4 saving afterwards. A mixed-age couple got UC in 2018 where the law allowed Pension Credit and pension-age HB, and a protected couple never got Pension Credit. Add meets_pension_credit_age_conditions (every adult over State Pension age, or a mixed-age couple before the exclusion or with the saving) and use it for Pension Credit, for new Housing Benefit claims (TP Regs reg 6A(4)-(5)) and, negated, for Universal Credit (TP Regs reg 5(1)(d): one route per family). The saving, has_mixed_age_couple_pension_credit_saving, is an input that defaults to reported Pension Credit or pension-age HB without reported UC, where the older member was born by 1954. Co-Authored-By: Claude Opus 5.5 --- .../pension-credit-mixed-age-saving.fixed.md | 1 + .../mixed_age_couples/excluded.yaml | 14 + .../saving_latest_birth_year.yaml | 13 + .../dwp/pension_credit/mixed_age_couples.yaml | 413 ++++++++++++++++++ ..._housing_benefit_pension_age_properties.py | 17 +- .../tests/test_mixed_age_couple_properties.py | 249 +++++++++++ .../housing_benefit_eligible.py | 33 +- .../is_pension_credit_eligible.py | 17 +- .../meets_pension_credit_age_conditions.py | 42 ++ ..._mixed_age_couple_pension_credit_saving.py | 62 +++ .../mixed_age_couples/is_mixed_age_couple.py | 30 ++ .../dwp/universal_credit/is_uc_eligible.py | 12 +- 12 files changed, 872 insertions(+), 31 deletions(-) create mode 100644 changelog.d/pension-credit-mixed-age-saving.fixed.md create mode 100644 policyengine_uk/parameters/gov/dwp/pension_credit/mixed_age_couples/excluded.yaml create mode 100644 policyengine_uk/parameters/gov/dwp/pension_credit/mixed_age_couples/saving_latest_birth_year.yaml create mode 100644 policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/mixed_age_couples.yaml create mode 100644 policyengine_uk/tests/test_mixed_age_couple_properties.py create mode 100644 policyengine_uk/variables/gov/dwp/pension_credit/meets_pension_credit_age_conditions.py create mode 100644 policyengine_uk/variables/gov/dwp/pension_credit/mixed_age_couples/has_mixed_age_couple_pension_credit_saving.py create mode 100644 policyengine_uk/variables/gov/dwp/pension_credit/mixed_age_couples/is_mixed_age_couple.py diff --git a/changelog.d/pension-credit-mixed-age-saving.fixed.md b/changelog.d/pension-credit-mixed-age-saving.fixed.md new file mode 100644 index 0000000000..bf1181fa6b --- /dev/null +++ b/changelog.d/pension-credit-mixed-age-saving.fixed.md @@ -0,0 +1 @@ +- Date the Pension Credit exclusion of mixed-age couples (State Pension Credit Act 2002 s.4(1A)) from 15 May 2019, and model the SI 2019/37 article 4 saving. Before the change, mixed-age couples could claim Pension Credit and pension-age Housing Benefit, and now take that route rather than Universal Credit. Afterwards, a couple entitled to Pension Credit or pension-age Housing Benefit on 14 May 2019 keeps them while it stays entitled. The saving is a new input, `has_mixed_age_couple_pension_credit_saving`, which by default is inferred from reported Pension Credit or pension-age Housing Benefit without reported Universal Credit, where the older member was born by 1954. A family on the Pension Credit route is no longer eligible for Universal Credit. diff --git a/policyengine_uk/parameters/gov/dwp/pension_credit/mixed_age_couples/excluded.yaml b/policyengine_uk/parameters/gov/dwp/pension_credit/mixed_age_couples/excluded.yaml new file mode 100644 index 0000000000..8f2358440e --- /dev/null +++ b/policyengine_uk/parameters/gov/dwp/pension_credit/mixed_age_couples/excluded.yaml @@ -0,0 +1,14 @@ +description: Whether a member of a mixed-age couple, where one partner has not reached the qualifying age for State Pension Credit, is excluded from State Pension Credit. The exclusion also bars the couple from new pension-age Housing Benefit claims. +values: + 2003-10-06: false + 2019-05-15: true +metadata: + unit: bool + label: Mixed-age couple exclusion from Pension Credit in force + reference: + - title: State Pension Credit Act 2002 s.4(1A) + href: https://www.legislation.gov.uk/ukpga/2002/16/section/4 + - title: SI 2019/37 art. 3 (appointed day 15 May 2019) + href: https://www.legislation.gov.uk/uksi/2019/37/article/3 + - title: SR 2019/4 art. 3 (Northern Ireland, appointed day 15 May 2019) + href: https://www.legislation.gov.uk/nisr/2019/4/article/3 diff --git a/policyengine_uk/parameters/gov/dwp/pension_credit/mixed_age_couples/saving_latest_birth_year.yaml b/policyengine_uk/parameters/gov/dwp/pension_credit/mixed_age_couples/saving_latest_birth_year.yaml new file mode 100644 index 0000000000..9207413045 --- /dev/null +++ b/policyengine_uk/parameters/gov/dwp/pension_credit/mixed_age_couples/saving_latest_birth_year.yaml @@ -0,0 +1,13 @@ +description: Latest birth year of the older member of a mixed-age couple for the couple to keep Pension Credit under the SI 2019/37 article 4 saving. The older member must have reached the qualifying age for State Pension Credit by 14 May 2019, which means being born on or before 5 February 1954. With whole-year ages the model admits the whole of 1954. +values: + 2019-05-15: 1954 +metadata: + unit: year + label: Latest birth year for the mixed-age couple Pension Credit saving + reference: + - title: SI 2019/37 art. 4(1) + href: https://www.legislation.gov.uk/uksi/2019/37/article/4 + - title: Pensions Act 1995 Sch 4 para 1 (pensionable age by date of birth) + href: https://www.legislation.gov.uk/ukpga/1995/26/schedule/4 + - title: State Pension Credit Act 2002 s.1(6) (qualifying age) + href: https://www.legislation.gov.uk/ukpga/2002/16/section/1 diff --git a/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/mixed_age_couples.yaml b/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/mixed_age_couples.yaml new file mode 100644 index 0000000000..42cead192e --- /dev/null +++ b/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/mixed_age_couples.yaml @@ -0,0 +1,413 @@ +# Mixed-age couples: State Pension Credit Act 2002 s.4(1A), in force 15 May +# 2019 (SI 2019/37 art. 3; NI: SR 2019/4 art. 3), with the SI 2019/37 art. 4 +# saving (NI: SR 2019/4 art. 4). Housing Benefit follows UC (Transitional +# Provisions) Regs 2014 reg 6A(4)-(5). +# +# Expected amounts are hand-computed from the law's rates: +# 2026-27 couple standard minimum guarantee GBP 363.25 a week: 363.25 x 52 = 18,889 +# 2018-19 couple standard minimum guarantee GBP 248.80 a week: 248.80 x 52 = 12,937.60 +# Guarantee Credit = minimum guarantee - income (State Pension 9,000 only) +# Housing Benefit on Guarantee Credit = full eligible rent (HB SPC Regs reg 26) + +- name: Protected mixed-age couple (art. 4 saving input) gets Pension Credit and HB, not UC + period: 2026 + absolute_error_margin: 0.01 + input: + people: + older: + age: 75 + state_pension: 9_000 + younger: + age: 60 + benunits: + benunit: + members: [older, younger] + has_mixed_age_couple_pension_credit_saving: true + households: + household: + members: [older, younger] + rent: 6_240 + tenure_type: RENT_FROM_COUNCIL + output: + is_mixed_age_couple: true + meets_pension_credit_age_conditions: true + is_pension_credit_eligible: true + guarantee_credit: 9_889 + pension_credit: 9_889 + housing_benefit_eligible: true + housing_benefit: 6_240 + is_uc_eligible: false + universal_credit: 0 + +- name: Reported Pension Credit sets the saving, whatever the UC take-up draw + period: 2026 + absolute_error_margin: 0.01 + input: + people: + older: + age: 75 + state_pension: 9_000 + pension_credit_reported: 1_000 + younger: + age: 60 + benunits: + benunit: + members: [older, younger] + would_claim_uc: true + households: + household: + members: [older, younger] + rent: 6_240 + tenure_type: RENT_FROM_COUNCIL + output: + has_mixed_age_couple_pension_credit_saving: true + pension_credit: 9_889 + universal_credit: 0 + +- name: Reported pension-age HB sets the saving + period: 2026 + absolute_error_margin: 0.01 + input: + people: + older: + age: 75 + state_pension: 9_000 + housing_benefit_reported: 5_000 + younger: + age: 60 + benunits: + benunit: + members: [older, younger] + households: + household: + members: [older, younger] + rent: 6_240 + tenure_type: RENT_FROM_COUNCIL + output: + has_mixed_age_couple_pension_credit_saving: true + is_pension_credit_eligible: true + housing_benefit: 6_240 + universal_credit: 0 + +- name: HB alongside income-related ESA is working-age HB, so no saving (art. 2(3); HB SPC Regs reg 5(2)) + period: 2026 + absolute_error_margin: 0.01 + input: + people: + older: + age: 75 + state_pension: 9_000 + housing_benefit_reported: 5_000 + esa_income_reported: 3_000 + younger: + age: 60 + benunits: + benunit: + members: [older, younger] + would_claim_uc: false + households: + household: + members: [older, younger] + rent: 6_240 + tenure_type: RENT_FROM_COUNCIL + output: + has_mixed_age_couple_pension_credit_saving: false + is_pension_credit_eligible: false + pension_credit: 0 + # continuing award route (TP reg 8(2A)), unchanged from main + housing_benefit_eligible: true + +- name: A UC award ends the saving (art. 4(2)) + period: 2026 + absolute_error_margin: 0.01 + input: + people: + older: + age: 75 + state_pension: 9_000 + pension_credit_reported: 1_000 + universal_credit_reported: 2_000 + younger: + age: 60 + benunits: + benunit: + members: [older, younger] + households: + household: + members: [older, younger] + rent: 6_240 + tenure_type: RENT_FROM_COUNCIL + output: + has_mixed_age_couple_pension_credit_saving: false + pension_credit: 0 + is_uc_eligible: true + +- name: The saving input can be switched off despite reported Pension Credit + period: 2026 + absolute_error_margin: 0.01 + input: + people: + older: + age: 75 + state_pension: 9_000 + pension_credit_reported: 1_000 + younger: + age: 60 + benunits: + benunit: + members: [older, younger] + has_mixed_age_couple_pension_credit_saving: false + households: + household: + members: [older, younger] + rent: 6_240 + tenure_type: RENT_FROM_COUNCIL + output: + is_pension_credit_eligible: false + pension_credit: 0 + is_uc_eligible: true + +- name: Unprotected mixed-age couple after 15 May 2019 claims UC, not PC or HB + period: 2026 + absolute_error_margin: 0.01 + input: + people: + older: + age: 70 + state_pension: 9_000 + younger: + age: 60 + benunits: + benunit: + members: [older, younger] + households: + household: + members: [older, younger] + rent: 6_240 + tenure_type: RENT_FROM_COUNCIL + output: + has_mixed_age_couple_pension_credit_saving: false + is_pension_credit_eligible: false + housing_benefit_eligible: false + is_uc_eligible: true + +- name: Before 15 May 2019 a mixed-age couple takes the Pension Credit route (2018-19) + period: 2018 + absolute_error_margin: 0.01 + input: + people: + older: + age: 70 + state_pension: 9_000 + younger: + age: 60 + benunits: + benunit: + members: [older, younger] + households: + household: + members: [older, younger] + rent: 6_240 + tenure_type: RENT_FROM_COUNCIL + output: + meets_pension_credit_age_conditions: true + guarantee_credit: 3_937.60 + pension_credit: 3_937.60 + housing_benefit: 6_240 + is_uc_eligible: false + universal_credit: 0 + +- name: Model year 2019 (2019-20, parameters read at 30 April 2019) is before the exclusion + period: 2019 + absolute_error_margin: 0.01 + input: + people: + older: + age: 70 + state_pension: 9_000 + younger: + age: 60 + benunits: + benunit: + members: [older, younger] + households: + household: + members: [older, younger] + rent: 6_240 + tenure_type: RENT_FROM_COUNCIL + output: + meets_pension_credit_age_conditions: true + is_uc_eligible: false + universal_credit: 0 + +- name: From model year 2020 an unprotected mixed-age couple is excluded + period: 2020 + absolute_error_margin: 0.01 + input: + people: + older: + age: 70 + state_pension: 9_000 + younger: + age: 60 + benunits: + benunit: + members: [older, younger] + households: + household: + members: [older, younger] + rent: 6_240 + tenure_type: RENT_FROM_COUNCIL + output: + meets_pension_credit_age_conditions: false + is_pension_credit_eligible: false + is_uc_eligible: true + +- name: Wholly pension-age couple is unaffected by the saving input + period: 2026 + absolute_error_margin: 0.01 + input: + people: + older: + age: 70 + state_pension: 9_000 + younger: + age: 68 + benunits: + benunit: + members: [older, younger] + has_mixed_age_couple_pension_credit_saving: true + households: + household: + members: [older, younger] + rent: 6_240 + tenure_type: RENT_FROM_COUNCIL + output: + is_mixed_age_couple: false + pension_credit: 9_889 + housing_benefit: 6_240 + universal_credit: 0 + +- name: Working-age couple is unaffected by the saving input + period: 2026 + absolute_error_margin: 0.01 + input: + people: + older: + age: 40 + younger: + age: 38 + benunits: + benunit: + members: [older, younger] + has_mixed_age_couple_pension_credit_saving: true + households: + household: + members: [older, younger] + rent: 6_240 + tenure_type: RENT_FROM_COUNCIL + output: + is_mixed_age_couple: false + meets_pension_credit_age_conditions: false + is_pension_credit_eligible: false + is_uc_eligible: true + +- name: Reported Pension Credit does not protect a couple whose older member reached pension age after 14 May 2019 + # 70 in 2026-27 means 63 on 14 May 2019, below the qualifying age (65 in the + # model's 2019 parameters), so the couple was not a mixed-age couple then. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + older: + age: 70 + state_pension: 9_000 + pension_credit_reported: 1_000 + younger: + age: 60 + benunits: + benunit: + members: [older, younger] + households: + household: + members: [older, younger] + rent: 6_240 + tenure_type: RENT_FROM_COUNCIL + output: + has_mixed_age_couple_pension_credit_saving: false + pension_credit: 0 + is_uc_eligible: true + +- name: Protected couple gets the pension-age couple HB allowance (HB SPC Regs Sch 3 para 1(2)(b)) + # 383.35 a week x 52 = 19,934.20 + period: 2026 + absolute_error_margin: 0.01 + input: + people: + older: + age: 75 + state_pension: 9_000 + pension_credit_reported: 1_000 + younger: + age: 60 + benunits: + benunit: + members: [older, younger] + households: + household: + members: [older, younger] + rent: 6_240 + tenure_type: RENT_FROM_COUNCIL + output: + housing_benefit_applicable_amount: 19_934.20 + +- name: Protected couple that does not take up Pension Credit gets neither PC nor UC, but keeps reported HB + period: 2026 + absolute_error_margin: 0.01 + input: + people: + older: + age: 75 + state_pension: 9_000 + housing_benefit_reported: 5_000 + younger: + age: 60 + benunits: + benunit: + members: [older, younger] + would_claim_pc: false + households: + household: + members: [older, younger] + rent: 6_240 + tenure_type: RENT_FROM_COUNCIL + output: + has_mixed_age_couple_pension_credit_saving: true + pension_credit: 0 + housing_benefit: 6_240 + universal_credit: 0 + +- name: Northern Ireland protected couple follows the same rule (SR 2019/4 art. 4) + period: 2026 + absolute_error_margin: 0.01 + input: + people: + older: + age: 75 + state_pension: 9_000 + pension_credit_reported: 1_000 + younger: + age: 60 + benunits: + benunit: + members: [older, younger] + households: + household: + members: [older, younger] + rent: 6_240 + tenure_type: RENT_FROM_COUNCIL + region: NORTHERN_IRELAND + output: + pension_credit: 9_889 + housing_benefit: 6_240 + universal_credit: 0 diff --git a/policyengine_uk/tests/test_housing_benefit_pension_age_properties.py b/policyengine_uk/tests/test_housing_benefit_pension_age_properties.py index 37672b3c3d..fba1b080a0 100644 --- a/policyengine_uk/tests/test_housing_benefit_pension_age_properties.py +++ b/policyengine_uk/tests/test_housing_benefit_pension_age_properties.py @@ -19,7 +19,9 @@ 3. Dataset mode (claims_all_entitled_benefits False, as in the FRS): Housing Benefit is paid only to reported claimants, and for families with a working-age adult eligibility equals the continuing-award rule (reported, - not claiming Universal Credit, renting, capital within the limit). + not claiming Universal Credit, renting, capital within the limit), or, + for a mixed-age couple keeping the SI 2019/37 art. 4 saving, the new-claim + rule (renting, capital within the limit; reg 6A(5)). 4. Metamorphic: flipping would_claim_uc never changes a wholly pension-age family's Housing Benefit. 5. Metamorphic: a wholly pension-age family's Housing Benefit is @@ -131,6 +133,7 @@ def situation(units, claims_all=None, flip_would_claim_uc=False, pension_bump=0. "benunit_rent", "LHA_eligible", "LHA_cap", + "has_mixed_age_couple_pension_credit_saving", ] @@ -196,13 +199,19 @@ def test_dataset_take_up_stays_anchored_to_reported_claims(units): if values["housing_benefit"][i] > 0: assert unit["hb_reported"] > 0, unit if not wholly_pension_age(unit): + renting_within_capital = values["renting"][i] and values["capital_ok"][i] continuing_award = ( unit["hb_reported"] > 0 and not unit["would_claim_uc"] - and values["renting"][i] - and values["capital_ok"][i] + and renting_within_capital ) - assert bool(values["housing_benefit_eligible"][i]) == continuing_award + saved_mixed_age_couple = ( + values["has_mixed_age_couple_pension_credit_saving"][i] + and renting_within_capital + ) + assert bool(values["housing_benefit_eligible"][i]) == ( + continuing_award or saved_mixed_age_couple + ), unit @PROPERTY_SETTINGS diff --git a/policyengine_uk/tests/test_mixed_age_couple_properties.py b/policyengine_uk/tests/test_mixed_age_couple_properties.py new file mode 100644 index 0000000000..0088007a8b --- /dev/null +++ b/policyengine_uk/tests/test_mixed_age_couple_properties.py @@ -0,0 +1,249 @@ +"""Mixed-age couples: State Pension Credit Act 2002 s.4(1A) and SI 2019/37. + +From 15 May 2019 (SI 2019/37 art. 3) a member of a couple whose partner has +not reached the qualifying age for State Pension Credit is not entitled to +it, and the couple claims Universal Credit instead. Couples entitled to +Pension Credit or pension-age Housing Benefit on 14 May 2019 keep them while +they stay entitled (art. 4). Before that date a mixed-age couple could claim +Pension Credit and pension-age Housing Benefit. + +Invariants, for every drawn household: + +P1 pension_credit > 0 implies universal_credit == 0. +P2 housing_benefit > 0 implies universal_credit == 0. +P3 meets_pension_credit_age_conditions implies not is_uc_eligible (UC + (Transitional Provisions) Regs 2014 reg 5(1)(d): one route per family). +P4 For a benefit unit that is not a mixed-age couple, the saving input + changes nothing. +P5 Differential against the formulas before this change: units that are + not mixed-age couples, and mixed-age couples without the saving from + model year 2020, get the same Pension Credit, Housing Benefit, Universal + Credit and household net income. +P6 From model year 2020, the saving never lowers Pension Credit or Housing + Benefit and leaves Universal Credit at 0. +P7 In model years 2018 and 2019 every mixed-age couple meets the Pension + Credit age conditions, whatever the saving input. +P8 The default saving is never set where the older member was born after + 1954 (so had not reached the qualifying age by 14 May 2019), or where + the couple reports Universal Credit. +""" + +import json + +from hypothesis import HealthCheck, given, settings +from hypothesis import strategies as st +from policyengine_core.reforms import Reform + +from policyengine_uk import Simulation +from policyengine_uk.model_api import * + +OUTPUTS = ["pension_credit", "housing_benefit", "universal_credit"] +SHAPES = [ + "single_pension", + "couple_pension", + "mixed", + "single_working", + "couple_working", +] +TENURES = ["RENT_FROM_COUNCIL", "RENT_PRIVATELY", "OWNED_OUTRIGHT"] + + +# The three eligibility formulas as they were before the mixed-age couple +# rules, kept verbatim as the reference for the differential invariant P5. +class is_pension_credit_eligible(Variable): + value_type = bool + entity = BenUnit + label = "Eligible for Pension Credit (before the mixed-age couple rules)" + definition_period = YEAR + + def formula(benunit, period, parameters): + adult = benunit.members("is_adult", period) + adult_count = benunit.sum(adult) + all_adults_are_sp_age = ( + benunit.sum(adult & benunit.members("is_SP_age", period)) == adult_count + ) + is_gc_eligible = benunit("is_guarantee_credit_eligible", period) + is_sc_eligible = benunit("is_savings_credit_eligible", period) + return ( + (adult_count > 0) + & all_adults_are_sp_age + & (is_gc_eligible | is_sc_eligible) + ) + + +class housing_benefit_eligible(Variable): + value_type = bool + entity = BenUnit + label = "Eligible for Housing Benefit (before the mixed-age couple rules)" + definition_period = YEAR + + def formula(benunit, period, parameters): + person = benunit.members + sp_age = person("is_SP_age", period) + adult = person("is_adult", period) + adult_count = benunit.sum(adult) + pension_age = (adult_count > 0) & (benunit.sum(adult & sp_age) == adult_count) + already_claiming = add(benunit, period, ["housing_benefit_reported"]) > 0 + claiming_uc = benunit("would_claim_uc", period) + continuing_award = already_claiming & ~claiming_uc + social = benunit.any(person("in_social_housing", period)) + lha_eligible = benunit("LHA_eligible", period) + any_over_SP_age = benunit.any(sp_age) + capital = benunit("housing_benefit_assessable_capital", period) + hb_capital = parameters(period).gov.dwp.housing_benefit.means_test.capital + limit = where( + any_over_SP_age, + hb_capital.pension_age.limit, + hb_capital.working_age.limit, + ) + return ( + (pension_age | continuing_award) + & (social | lha_eligible) + & (capital <= limit) + ) + + +class is_uc_eligible(Variable): + value_type = bool + entity = BenUnit + label = "Eligible for Universal Credit (before the mixed-age couple rules)" + definition_period = YEAR + + def formula(benunit, period, parameters): + capital = benunit("uc_assessable_capital", period) + limit = parameters(period).gov.dwp.universal_credit.means_test.capital.limit + has_working_age_adult = benunit.any(benunit.members("is_WA_adult", period)) + return has_working_age_adult & (capital <= limit) + + +class before_mixed_age_couple_rules(Reform): + def apply(self): + self.update_variable(is_pension_credit_eligible) + self.update_variable(housing_benefit_eligible) + self.update_variable(is_uc_eligible) + + +@st.composite +def cases(draw): + year = draw(st.sampled_from([2018, 2019, 2020, 2025, 2026])) + shape = draw(st.sampled_from(SHAPES)) + pension_age = st.integers(67, 90) + working_age = st.integers(25, 59) + older_is_pension_age = "pension" in shape or shape == "mixed" + people = { + "older": {"age": draw(pension_age if older_is_pension_age else working_age)} + } + if shape.startswith("couple") or shape == "mixed": + people["younger"] = { + "age": draw(pension_age if shape == "couple_pension" else working_age) + } + for person in people.values(): + if person["age"] >= 67: + person["state_pension"] = draw(st.integers(0, 15_000)) + else: + person["employment_income"] = draw( + st.sampled_from([0, 0, 5_000, 15_000, 30_000]) + ) + older = people["older"] + older["pension_credit_reported"] = draw(st.sampled_from([0, 0, 1_000])) + older["housing_benefit_reported"] = draw(st.sampled_from([0, 0, 4_000])) + older["universal_credit_reported"] = draw(st.sampled_from([0, 0, 0, 2_000])) + older["esa_income_reported"] = draw(st.sampled_from([0, 0, 0, 3_000])) + tenure = draw(st.sampled_from(TENURES)) + return { + "year": year, + "shape": shape, + "people": people, + "benunit": { + "would_claim_uc": draw(st.booleans()), + "would_claim_pc": draw(st.booleans()), + "BRMA_LHA_rate": draw(st.integers(4_000, 12_000)), + }, + "household": { + "tenure_type": tenure, + "rent": 0 if tenure == "OWNED_OUTRIGHT" else draw(st.integers(0, 12_000)), + "savings": draw(st.sampled_from([0, 5_000, 20_000])), + "region": "NORTH_WEST", + "council_tax": 1_500, + }, + } + + +def situation(case): + year = case["year"] + + def at_year(values): + return {name: {year: value} for name, value in values.items()} + + members = list(case["people"]) + return { + "people": {name: at_year(p) for name, p in case["people"].items()}, + "benunits": {"b": {"members": members, **at_year(case["benunit"])}}, + "households": {"h": {"members": members, **at_year(case["household"])}}, + } + + +def run(case, before=False, saving=None): + simulation = Simulation(situation=situation(case)) + year = case["year"] + if before: + simulation.apply_reform(before_mixed_age_couple_rules) + elif saving is not None: + simulation.set_input( + "has_mixed_age_couple_pension_credit_saving", year, [saving] + ) + + def get(variable): + return simulation.calculate(variable, year)[0] + + result = {variable: float(get(variable)) for variable in OUTPUTS} + result["net"] = float(get("household_net_income")) + if not before: + result["age_conditions"] = bool(get("meets_pension_credit_age_conditions")) + result["uc_eligible"] = bool(get("is_uc_eligible")) + result["mixed"] = bool(get("is_mixed_age_couple")) + result["saving"] = bool(get("has_mixed_age_couple_pension_credit_saving")) + return result + + +def close(a, b): + return abs(a - b) < 0.01 + + +@settings( + max_examples=40, + deadline=None, + derandomize=True, + suppress_health_check=[HealthCheck.too_slow], +) +@given(cases()) +def test_mixed_age_couple_invariants(case): + before = run(case, before=True) + on = run(case, saving=True) + off = run(case, saving=False) + default = run(case) + context = json.dumps(case) + for result in (on, off, default): + assert not (result["pension_credit"] > 0 and result["universal_credit"] > 0) + assert not (result["housing_benefit"] > 0 and result["universal_credit"] > 0) + assert not (result["age_conditions"] and result["uc_eligible"]), context + mixed = on["mixed"] + assert mixed == (case["shape"] == "mixed"), context + if not mixed: + for variable in OUTPUTS + ["net"]: + assert close(on[variable], off[variable]), (variable, context) # P4 + assert close(on[variable], default[variable]), (variable, context) + assert close(off[variable], before[variable]), (variable, context) # P5 + elif case["year"] >= 2020: + for variable in OUTPUTS + ["net"]: + assert close(off[variable], before[variable]), (variable, context) # P5 + assert on["pension_credit"] >= off["pension_credit"] - 0.01, context # P6 + assert on["housing_benefit"] >= off["housing_benefit"] - 0.01, context + assert on["universal_credit"] == 0, context + else: + assert on["age_conditions"] and off["age_conditions"], context # P7 + assert default["age_conditions"], context + older = case["people"]["older"] + if default["saving"]: # P8 + assert case["year"] - older["age"] <= 1954, context + assert older["universal_credit_reported"] == 0, context diff --git a/policyengine_uk/variables/gov/dwp/housing_benefit/housing_benefit_eligible.py b/policyengine_uk/variables/gov/dwp/housing_benefit/housing_benefit_eligible.py index 9cab415763..bc5a516e8e 100644 --- a/policyengine_uk/variables/gov/dwp/housing_benefit/housing_benefit_eligible.py +++ b/policyengine_uk/variables/gov/dwp/housing_benefit/housing_benefit_eligible.py @@ -17,6 +17,7 @@ class housing_benefit_eligible(Variable): definition_period = YEAR reference = ( "https://www.legislation.gov.uk/uksi/2014/1230/regulation/6A", + "https://www.legislation.gov.uk/ukpga/2002/16/section/4", "https://www.legislation.gov.uk/uksi/2014/1230/regulation/8", "https://www.legislation.gov.uk/uksi/2019/37/article/4", "https://www.legislation.gov.uk/ukpga/2012/5/section/4", @@ -28,22 +29,22 @@ def formula(benunit, period, parameters): sp_age = person("is_SP_age", period) # New claims are barred except where the claimant, and any partner, # has reached the qualifying age for State Pension Credit - # (SI 2014/1230 reg 6A(4); NI: SR 2016/226 reg 4A(4)). Every adult in - # the benefit unit stands in for the claimant and partner, as in - # is_uc_eligible and is_pension_credit_eligible, so a pensioner with - # an 18 or 19 year old dependant is routed to Universal Credit. - # Because is_uc_eligible needs a working-age adult, no family on this - # route receives Universal Credit; change the three together. - adult = person("is_adult", period) - adult_count = benunit.sum(adult) - pension_age = (adult_count > 0) & (benunit.sum(adult & sp_age) == adult_count) - # Working-age and mixed-age families (since 15 May 2019) claim - # Universal Credit instead. They keep an existing award until they - # claim it (reg 8(2A)), so this route also rules out receiving - # Universal Credit. For mixed-age couples the reported award stands - # in for the SI 2019/37 art. 4 saving (reg 6A(5)). Working-age awards - # outside specified or temporary accommodation ended on 1 July 2026 - # in Great Britain (SI 2025/1148 art. 7); that is not modelled. + # (SI 2014/1230 reg 6A(4); NI: SR 2016/226 reg 4A(4)), or the claim + # is made by the older member of a mixed-age couple that keeps the + # SI 2019/37 art. 4 saving (reg 6A(5); NI reg 4A(5)). Before 15 May + # 2019 mixed-age couples could claim too. These are the Pension + # Credit age conditions, which also rule out Universal Credit + # (is_uc_eligible), so no family on this route receives it. Every + # adult in the benefit unit stands in for the claimant and partner, + # so a single pensioner with an 18 or 19 year old dependant is routed + # to Universal Credit. + pension_age = benunit("meets_pension_credit_age_conditions", period) + # Working-age families, and mixed-age couples without the saving + # (since 15 May 2019), claim Universal Credit instead. They keep an + # existing award until they claim it (reg 8(2A)), so this route also + # rules out receiving Universal Credit. Working-age awards outside + # specified or temporary accommodation ended on 1 July 2026 in Great + # Britain (SI 2025/1148 art. 7); that is not modelled. already_claiming = add(benunit, period, ["housing_benefit_reported"]) > 0 claiming_uc = benunit("would_claim_uc", period) continuing_award = already_claiming & ~claiming_uc diff --git a/policyengine_uk/variables/gov/dwp/pension_credit/is_pension_credit_eligible.py b/policyengine_uk/variables/gov/dwp/pension_credit/is_pension_credit_eligible.py index d3c12d4372..d970390993 100644 --- a/policyengine_uk/variables/gov/dwp/pension_credit/is_pension_credit_eligible.py +++ b/policyengine_uk/variables/gov/dwp/pension_credit/is_pension_credit_eligible.py @@ -7,18 +7,15 @@ class is_pension_credit_eligible(Variable): definition_period = YEAR value_type = bool unit = GBP - reference = "https://www.legislation.gov.uk/ukpga/2002/16/section/1" + reference = ( + "https://www.legislation.gov.uk/ukpga/2002/16/section/1", + "https://www.legislation.gov.uk/ukpga/2002/16/section/4", + "https://www.legislation.gov.uk/uksi/2019/37/article/4", + ) def formula(benunit, period, parameters): - adult = benunit.members("is_adult", period) - adult_count = benunit.sum(adult) - all_adults_are_sp_age = ( - benunit.sum(adult & benunit.members("is_SP_age", period)) == adult_count - ) is_gc_eligible = benunit("is_guarantee_credit_eligible", period) is_sc_eligible = benunit("is_savings_credit_eligible", period) - return ( - (adult_count > 0) - & all_adults_are_sp_age - & (is_gc_eligible | is_sc_eligible) + return benunit("meets_pension_credit_age_conditions", period) & ( + is_gc_eligible | is_sc_eligible ) diff --git a/policyengine_uk/variables/gov/dwp/pension_credit/meets_pension_credit_age_conditions.py b/policyengine_uk/variables/gov/dwp/pension_credit/meets_pension_credit_age_conditions.py new file mode 100644 index 0000000000..edad858db4 --- /dev/null +++ b/policyengine_uk/variables/gov/dwp/pension_credit/meets_pension_credit_age_conditions.py @@ -0,0 +1,42 @@ +from policyengine_uk.model_api import * + + +class meets_pension_credit_age_conditions(Variable): + value_type = bool + entity = BenUnit + label = "Meets the State Pension Credit age conditions" + documentation = ( + "The claimant has reached the qualifying age for State Pension Credit " + "and, while the mixed-age couple exclusion is in force (from 15 May " + "2019), so has any partner, unless the couple keeps Pension Credit " + "under the SI 2019/37 article 4 saving. A family meeting these " + "conditions is on the pension-age route (Pension Credit and pension-age " + "Housing Benefit) and is not eligible for Universal Credit." + ) + definition_period = YEAR + reference = ( + "https://www.legislation.gov.uk/ukpga/2002/16/section/1", + "https://www.legislation.gov.uk/ukpga/2002/16/section/4", + "https://www.legislation.gov.uk/uksi/2019/37/article/4", + "https://www.legislation.gov.uk/uksi/2014/1230/regulation/5", + "https://www.legislation.gov.uk/uksi/2014/1230/regulation/6A", + ) + + def formula(benunit, period, parameters): + person = benunit.members + adult = person("is_adult", period) + adult_count = benunit.sum(adult) + all_pension_age = (adult_count > 0) & ( + benunit.sum(adult & person("is_SP_age", period)) == adult_count + ) + # Parameters are read at 30 April of the model year + # (convert_to_fiscal_year_parameters), so model year 2019 (2019-20) + # falls before the 15 May 2019 exclusion. Couples already on Pension + # Credit or pension-age Housing Benefit on 14 May 2019 kept them, so + # the old rule is the closer approximation for that year. + excluded = parameters(period).gov.dwp.pension_credit.mixed_age_couples.excluded + saving = benunit("has_mixed_age_couple_pension_credit_saving", period) + mixed_age_route = benunit("is_mixed_age_couple", period) & ( + np.logical_not(excluded) | saving + ) + return all_pension_age | mixed_age_route diff --git a/policyengine_uk/variables/gov/dwp/pension_credit/mixed_age_couples/has_mixed_age_couple_pension_credit_saving.py b/policyengine_uk/variables/gov/dwp/pension_credit/mixed_age_couples/has_mixed_age_couple_pension_credit_saving.py new file mode 100644 index 0000000000..d95789d7a1 --- /dev/null +++ b/policyengine_uk/variables/gov/dwp/pension_credit/mixed_age_couples/has_mixed_age_couple_pension_credit_saving.py @@ -0,0 +1,62 @@ +from policyengine_uk.model_api import * + + +class has_mixed_age_couple_pension_credit_saving(Variable): + value_type = bool + entity = BenUnit + label = "Mixed-age couple keeps Pension Credit under the SI 2019/37 saving" + documentation = ( + "Whether the State Pension Credit Act 2002 s.4(1A) exclusion does not " + "apply to a mixed-age couple, because on 14 May 2019 the couple was " + "entitled, as that couple, to Pension Credit or pension-age Housing " + "Benefit, and has been entitled to one of them ever since. Set it as " + "an input where it is known. By default it is inferred from current " + "receipt: reported Pension Credit, or reported Housing Benefit without " + "Income Support, income-based JSA or income-related ESA (which would " + "put the couple under the working-age Housing Benefit Regulations), " + "with no reported Universal Credit, where the older member was born " + "early enough to have reached the qualifying age by 14 May 2019." + ) + definition_period = YEAR + reference = ( + "https://www.legislation.gov.uk/uksi/2019/37/article/2", + "https://www.legislation.gov.uk/uksi/2019/37/article/4", + "https://www.legislation.gov.uk/uksi/2006/214/regulation/5", + "https://www.legislation.gov.uk/uksi/2014/1230/regulation/5", + "https://www.legislation.gov.uk/nisr/2019/4/article/4", + ) + + def formula(benunit, period, parameters): + p = parameters(period).gov.dwp.pension_credit.mixed_age_couples + + def reported(variables): + return add(benunit, period, variables) > 0 + + # Art. 2(3): only Housing Benefit under the pension-age regulations + # (SI 2006/214) carries the saving; a couple on an income-related + # legacy benefit is under the working-age regulations (reg 5(2)). + pension_age_hb = reported(["housing_benefit_reported"]) & ~reported( + [ + "income_support_reported", + "jsa_income_reported", + "esa_income_reported", + ] + ) + # Art. 4(2) ends the saving once the couple is entitled to neither + # benefit, which Universal Credit entitlement implies (TP Regs 2014 + # reg 5(1)(d)). + receives_uc = reported(["universal_credit_reported"]) + # Art. 4(1) needs the couple to have been a mixed-age couple on + # 14 May 2019, so its older member had reached the qualifying age by + # then. + person = benunit.members + older_member_qualified = benunit.any( + person("is_SP_age", period) + & (person("birth_year", period) <= p.saving_latest_birth_year) + ) + return ( + benunit("is_mixed_age_couple", period) + & older_member_qualified + & (reported(["pension_credit_reported"]) | pension_age_hb) + & ~receives_uc + ) diff --git a/policyengine_uk/variables/gov/dwp/pension_credit/mixed_age_couples/is_mixed_age_couple.py b/policyengine_uk/variables/gov/dwp/pension_credit/mixed_age_couples/is_mixed_age_couple.py new file mode 100644 index 0000000000..6189a4d38d --- /dev/null +++ b/policyengine_uk/variables/gov/dwp/pension_credit/mixed_age_couples/is_mixed_age_couple.py @@ -0,0 +1,30 @@ +from policyengine_uk.model_api import * + + +class is_mixed_age_couple(Variable): + value_type = bool + entity = BenUnit + label = "Mixed-age couple" + documentation = ( + "A couple one member of which has reached the qualifying age for State " + "Pension Credit and the other of which has not." + ) + definition_period = YEAR + reference = ( + "https://www.legislation.gov.uk/uksi/2019/37/article/2", + "https://www.legislation.gov.uk/ukpga/2002/16/section/4", + ) + + def formula(benunit, period, parameters): + person = benunit.members + # Every adult in the benefit unit stands in for the claimant and + # partner, as in is_pension_credit_eligible and is_uc_eligible, so a + # pensioner couple with an 18 or 19 year old dependant also counts. + adult = person("is_adult", period) + pension_age = person("is_SP_age", period) + n_pension_age = benunit.sum(adult & pension_age) + return ( + benunit("is_couple", period) + & (n_pension_age > 0) + & (n_pension_age < benunit.sum(adult)) + ) diff --git a/policyengine_uk/variables/gov/dwp/universal_credit/is_uc_eligible.py b/policyengine_uk/variables/gov/dwp/universal_credit/is_uc_eligible.py index 2dbd88a4f9..de18f6d4ea 100644 --- a/policyengine_uk/variables/gov/dwp/universal_credit/is_uc_eligible.py +++ b/policyengine_uk/variables/gov/dwp/universal_credit/is_uc_eligible.py @@ -7,9 +7,19 @@ class is_uc_eligible(Variable): label = "Eligible for the Universal Credit" documentation = "Whether this family is eligible for Universal Credit" definition_period = YEAR + reference = ( + "https://www.legislation.gov.uk/ukpga/2012/5/section/4", + "https://www.legislation.gov.uk/uksi/2013/376/regulation/3", + "https://www.legislation.gov.uk/uksi/2014/1230/regulation/5", + ) def formula(benunit, period, parameters): capital = benunit("uc_assessable_capital", period) limit = parameters(period).gov.dwp.universal_credit.means_test.capital.limit has_working_age_adult = benunit.any(benunit.members("is_WA_adult", period)) - return has_working_age_adult & (capital <= limit) + # A family on the Pension Credit route cannot also have Universal + # Credit (UC (Transitional Provisions) Regs 2014 reg 5(1)(d)). This + # sends mixed-age couples keeping the SI 2019/37 saving, and every + # mixed-age couple before 15 May 2019, to Pension Credit. + pension_credit_route = benunit("meets_pension_credit_age_conditions", period) + return has_working_age_adult & ~pension_credit_route & (capital <= limit) From 24f59a42a5d09acff62f33112943122eaad9ebf9 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Wed, 30 Sep 2026 14:15:45 -0400 Subject: [PATCH 2/4] Tighten the mixed-age couple test and saving per review - is_mixed_age_couple counts only the claimant and partner (adults who are not a child or qualifying young person for Pension Credit), so a single pensioner with an 18 or 19 year old dependant in education is not a mixed-age couple and stays on main's route. - Only Housing Benefit reported by the pension-age member sets the SI 2019/37 saving: art. 2(3) counts HB under the pension-age regulations, which apply to a claimant over the qualifying age (HB(SPC) reg 5(1)). - Before 15 May 2019 a couple reported on Universal Credit stays on it. - State the Pension Credit routing of saved couples and pre-2019 couples as modelling choices, not a consequence of TP Regs reg 5(1)(d). - The HB dataset-mode invariant computes the expected saving from the drawn unit rather than from model output; the mixed-age properties draw dependant shapes. Four YAML cases added. Co-Authored-By: Claude Opus 5.5 --- .../dwp/pension_credit/mixed_age_couples.yaml | 105 ++++++++++++++++++ ..._housing_benefit_pension_age_properties.py | 15 ++- .../tests/test_mixed_age_couple_properties.py | 35 ++++-- .../housing_benefit_eligible.py | 8 +- .../meets_pension_credit_age_conditions.py | 8 +- ..._mixed_age_couple_pension_credit_saving.py | 22 +++- .../mixed_age_couples/is_mixed_age_couple.py | 18 ++- .../dwp/universal_credit/is_uc_eligible.py | 12 +- 8 files changed, 185 insertions(+), 38 deletions(-) diff --git a/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/mixed_age_couples.yaml b/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/mixed_age_couples.yaml index 42cead192e..3a3a28ece7 100644 --- a/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/mixed_age_couples.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/mixed_age_couples.yaml @@ -411,3 +411,108 @@ pension_credit: 9_889 housing_benefit: 6_240 universal_credit: 0 + +- name: A single pensioner with an 18 year old dependant in education is not a mixed-age couple + period: 2026 + absolute_error_margin: 0.01 + input: + people: + pensioner: + age: 75 + state_pension: 9_000 + pension_credit_reported: 1_000 + is_parent: true + dependant: + age: 18 + current_education: UPPER_SECONDARY + benunits: + benunit: + members: [pensioner, dependant] + households: + household: + members: [pensioner, dependant] + rent: 6_240 + tenure_type: RENT_FROM_COUNCIL + output: + is_child_or_qualifying_young_person_for_pension_credit: [false, true] + is_mixed_age_couple: false + has_mixed_age_couple_pension_credit_saving: false + meets_pension_credit_age_conditions: false + +- name: A mixed-age couple with an 18 year old dependant in education can keep the saving + period: 2026 + absolute_error_margin: 0.01 + input: + people: + older: + age: 75 + state_pension: 9_000 + pension_credit_reported: 1_000 + is_parent: true + younger: + age: 60 + dependant: + age: 18 + current_education: UPPER_SECONDARY + benunits: + benunit: + members: [older, younger, dependant] + households: + household: + members: [older, younger, dependant] + rent: 6_240 + tenure_type: RENT_FROM_COUNCIL + output: + is_mixed_age_couple: true + has_mixed_age_couple_pension_credit_saving: true + is_uc_eligible: false + universal_credit: 0 + +- name: Housing Benefit reported by the younger member does not set the saving (HB SPC Regs reg 5(1)) + period: 2026 + absolute_error_margin: 0.01 + input: + people: + older: + age: 75 + state_pension: 9_000 + younger: + age: 60 + housing_benefit_reported: 5_000 + benunits: + benunit: + members: [older, younger] + households: + household: + members: [older, younger] + rent: 6_240 + tenure_type: RENT_FROM_COUNCIL + output: + has_mixed_age_couple_pension_credit_saving: false + meets_pension_credit_age_conditions: false + pension_credit: 0 + +- name: Before 15 May 2019 a mixed-age couple reported on Universal Credit stays on it + period: 2018 + absolute_error_margin: 0.01 + input: + people: + older: + age: 70 + state_pension: 9_000 + universal_credit_reported: 2_000 + younger: + age: 60 + benunits: + benunit: + members: [older, younger] + households: + household: + members: [older, younger] + rent: 6_240 + tenure_type: RENT_FROM_COUNCIL + output: + is_mixed_age_couple: true + meets_pension_credit_age_conditions: false + is_pension_credit_eligible: false + is_uc_eligible: true diff --git a/policyengine_uk/tests/test_housing_benefit_pension_age_properties.py b/policyengine_uk/tests/test_housing_benefit_pension_age_properties.py index fba1b080a0..0341ff6615 100644 --- a/policyengine_uk/tests/test_housing_benefit_pension_age_properties.py +++ b/policyengine_uk/tests/test_housing_benefit_pension_age_properties.py @@ -28,8 +28,9 @@ non-increasing in private pension income. A pensioner with an 18 or 19 year old dependant counts as having a working-age -adult for Housing Benefit, Pension Credit and Universal Credit alike, so the -mutual exclusion holds for that shape too. +adult for Housing Benefit, Pension Credit and Universal Credit alike (it is not +a mixed-age couple, whose claimant and partner exclude a qualifying young +person), so the mutual exclusion holds for that shape too. """ import numpy as np @@ -133,7 +134,6 @@ def situation(units, claims_all=None, flip_would_claim_uc=False, pension_bump=0. "benunit_rent", "LHA_eligible", "LHA_cap", - "has_mixed_age_couple_pension_credit_saving", ] @@ -205,8 +205,15 @@ def test_dataset_take_up_stays_anchored_to_reported_claims(units): and not unit["would_claim_uc"] and renting_within_capital ) + # SI 2019/37 art. 4 saving, computed from the drawn unit rather + # than the model: a mixed-age couple whose pension-age claimant + # reports Housing Benefit (no UC or legacy benefits are drawn) + # and was born by 1954 (over the qualifying age on 14 May 2019). + claimant_age = unit["members"][0][1] saved_mixed_age_couple = ( - values["has_mixed_age_couple_pension_credit_saving"][i] + unit["shape"] == "mixed_age" + and unit["hb_reported"] > 0 + and YEAR - claimant_age <= 1954 and renting_within_capital ) assert bool(values["housing_benefit_eligible"][i]) == ( diff --git a/policyengine_uk/tests/test_mixed_age_couple_properties.py b/policyengine_uk/tests/test_mixed_age_couple_properties.py index 0088007a8b..18a8b8b7ac 100644 --- a/policyengine_uk/tests/test_mixed_age_couple_properties.py +++ b/policyengine_uk/tests/test_mixed_age_couple_properties.py @@ -21,8 +21,9 @@ Credit and household net income. P6 From model year 2020, the saving never lowers Pension Credit or Housing Benefit and leaves Universal Credit at 0. -P7 In model years 2018 and 2019 every mixed-age couple meets the Pension - Credit age conditions, whatever the saving input. +P7 In model years 2018 and 2019 every mixed-age couple not reported on + Universal Credit meets the Pension Credit age conditions, whatever the + saving input; one reported on UC meets them only with the saving. P8 The default saving is never set where the older member was born after 1954 (so had not reached the qualifying age by 14 May 2019), or where the couple reports Universal Credit. @@ -44,7 +45,13 @@ "mixed", "single_working", "couple_working", + # An 18 year old dependant in upper secondary education is a qualifying + # young person for Pension Credit, not a partner. + "single_pension_with_dependant", + "couple_pension_with_dependant", + "mixed_with_dependant", ] +MIXED_AGE_COUPLE_SHAPES = {"mixed", "mixed_with_dependant"} TENURES = ["RENT_FROM_COUNCIL", "RENT_PRIVATELY", "OWNED_OUTRIGHT"] @@ -129,15 +136,22 @@ def cases(draw): shape = draw(st.sampled_from(SHAPES)) pension_age = st.integers(67, 90) working_age = st.integers(25, 59) - older_is_pension_age = "pension" in shape or shape == "mixed" + older_is_pension_age = "pension" in shape or shape.startswith("mixed") people = { "older": {"age": draw(pension_age if older_is_pension_age else working_age)} } - if shape.startswith("couple") or shape == "mixed": + if shape.startswith("couple") or shape.startswith("mixed"): people["younger"] = { - "age": draw(pension_age if shape == "couple_pension" else working_age) + "age": draw( + pension_age if shape.startswith("couple_pension") else working_age + ) } - for person in people.values(): + if shape.endswith("with_dependant"): + people["dependant"] = {"age": 18, "current_education": "UPPER_SECONDARY"} + people["older"]["is_parent"] = True + for name, person in people.items(): + if name == "dependant": + continue if person["age"] >= 67: person["state_pension"] = draw(st.integers(0, 15_000)) else: @@ -228,7 +242,7 @@ def test_mixed_age_couple_invariants(case): assert not (result["housing_benefit"] > 0 and result["universal_credit"] > 0) assert not (result["age_conditions"] and result["uc_eligible"]), context mixed = on["mixed"] - assert mixed == (case["shape"] == "mixed"), context + assert mixed == (case["shape"] in MIXED_AGE_COUPLE_SHAPES), context if not mixed: for variable in OUTPUTS + ["net"]: assert close(on[variable], off[variable]), (variable, context) # P4 @@ -241,8 +255,11 @@ def test_mixed_age_couple_invariants(case): assert on["housing_benefit"] >= off["housing_benefit"] - 0.01, context assert on["universal_credit"] == 0, context else: - assert on["age_conditions"] and off["age_conditions"], context # P7 - assert default["age_conditions"], context + # P7: before the exclusion only a couple reported on UC stays on it. + on_uc = case["people"]["older"]["universal_credit_reported"] > 0 + assert on["age_conditions"], context + assert off["age_conditions"] == (not on_uc), context + assert default["age_conditions"] == (not on_uc), context older = case["people"]["older"] if default["saving"]: # P8 assert case["year"] - older["age"] <= 1954, context diff --git a/policyengine_uk/variables/gov/dwp/housing_benefit/housing_benefit_eligible.py b/policyengine_uk/variables/gov/dwp/housing_benefit/housing_benefit_eligible.py index bc5a516e8e..0519ca2edc 100644 --- a/policyengine_uk/variables/gov/dwp/housing_benefit/housing_benefit_eligible.py +++ b/policyengine_uk/variables/gov/dwp/housing_benefit/housing_benefit_eligible.py @@ -34,10 +34,10 @@ def formula(benunit, period, parameters): # SI 2019/37 art. 4 saving (reg 6A(5); NI reg 4A(5)). Before 15 May # 2019 mixed-age couples could claim too. These are the Pension # Credit age conditions, which also rule out Universal Credit - # (is_uc_eligible), so no family on this route receives it. Every - # adult in the benefit unit stands in for the claimant and partner, - # so a single pensioner with an 18 or 19 year old dependant is routed - # to Universal Credit. + # (is_uc_eligible), so no family on this route receives it. Outside + # mixed-age couples every adult in the benefit unit stands in for the + # claimant and partner, so a pensioner with an 18 or 19 year old + # dependant is routed to Universal Credit. pension_age = benunit("meets_pension_credit_age_conditions", period) # Working-age families, and mixed-age couples without the saving # (since 15 May 2019), claim Universal Credit instead. They keep an diff --git a/policyengine_uk/variables/gov/dwp/pension_credit/meets_pension_credit_age_conditions.py b/policyengine_uk/variables/gov/dwp/pension_credit/meets_pension_credit_age_conditions.py index edad858db4..3c09d66cc8 100644 --- a/policyengine_uk/variables/gov/dwp/pension_credit/meets_pension_credit_age_conditions.py +++ b/policyengine_uk/variables/gov/dwp/pension_credit/meets_pension_credit_age_conditions.py @@ -36,7 +36,13 @@ def formula(benunit, period, parameters): # the old rule is the closer approximation for that year. excluded = parameters(period).gov.dwp.pension_credit.mixed_age_couples.excluded saving = benunit("has_mixed_age_couple_pension_credit_saving", period) + # Before the exclusion a mixed-age couple could claim either Pension + # Credit or Universal Credit jointly (UC Regs 2013 reg 3(2)(a)); a + # couple reported on Universal Credit stays on it, and any other takes + # the Pension Credit route. This is a modelling choice. + reports_uc = add(benunit, period, ["universal_credit_reported"]) > 0 + before_exclusion = np.logical_not(excluded) & ~reports_uc mixed_age_route = benunit("is_mixed_age_couple", period) & ( - np.logical_not(excluded) | saving + before_exclusion | saving ) return all_pension_age | mixed_age_route diff --git a/policyengine_uk/variables/gov/dwp/pension_credit/mixed_age_couples/has_mixed_age_couple_pension_credit_saving.py b/policyengine_uk/variables/gov/dwp/pension_credit/mixed_age_couples/has_mixed_age_couple_pension_credit_saving.py index d95789d7a1..6ae566b4a5 100644 --- a/policyengine_uk/variables/gov/dwp/pension_credit/mixed_age_couples/has_mixed_age_couple_pension_credit_saving.py +++ b/policyengine_uk/variables/gov/dwp/pension_credit/mixed_age_couples/has_mixed_age_couple_pension_credit_saving.py @@ -11,8 +11,9 @@ class has_mixed_age_couple_pension_credit_saving(Variable): "entitled, as that couple, to Pension Credit or pension-age Housing " "Benefit, and has been entitled to one of them ever since. Set it as " "an input where it is known. By default it is inferred from current " - "receipt: reported Pension Credit, or reported Housing Benefit without " - "Income Support, income-based JSA or income-related ESA (which would " + "receipt: reported Pension Credit, or Housing Benefit reported by the " + "pension-age member without Income Support, income-based JSA or " + "income-related ESA (which would " "put the couple under the working-age Housing Benefit Regulations), " "with no reported Universal Credit, where the older member was born " "early enough to have reached the qualifying age by 14 May 2019." @@ -33,9 +34,19 @@ def reported(variables): return add(benunit, period, variables) > 0 # Art. 2(3): only Housing Benefit under the pension-age regulations - # (SI 2006/214) carries the saving; a couple on an income-related - # legacy benefit is under the working-age regulations (reg 5(2)). - pension_age_hb = reported(["housing_benefit_reported"]) & ~reported( + # (SI 2006/214) carries the saving. They apply to a claimant who has + # reached the qualifying age (reg 5(1)), so only HB reported by the + # pension-age member counts, and not where the couple is on an + # income-related legacy benefit, which puts it under the working-age + # regulations (reg 5(2)). + person = benunit.members + pension_age_member_hb = ( + benunit.sum( + person("housing_benefit_reported", period) * person("is_SP_age", period) + ) + > 0 + ) + pension_age_hb = pension_age_member_hb & ~reported( [ "income_support_reported", "jsa_income_reported", @@ -49,7 +60,6 @@ def reported(variables): # Art. 4(1) needs the couple to have been a mixed-age couple on # 14 May 2019, so its older member had reached the qualifying age by # then. - person = benunit.members older_member_qualified = benunit.any( person("is_SP_age", period) & (person("birth_year", period) <= p.saving_latest_birth_year) diff --git a/policyengine_uk/variables/gov/dwp/pension_credit/mixed_age_couples/is_mixed_age_couple.py b/policyengine_uk/variables/gov/dwp/pension_credit/mixed_age_couples/is_mixed_age_couple.py index 6189a4d38d..4015fe084e 100644 --- a/policyengine_uk/variables/gov/dwp/pension_credit/mixed_age_couples/is_mixed_age_couple.py +++ b/policyengine_uk/variables/gov/dwp/pension_credit/mixed_age_couples/is_mixed_age_couple.py @@ -17,14 +17,12 @@ class is_mixed_age_couple(Variable): def formula(benunit, period, parameters): person = benunit.members - # Every adult in the benefit unit stands in for the claimant and - # partner, as in is_pension_credit_eligible and is_uc_eligible, so a - # pensioner couple with an 18 or 19 year old dependant also counts. - adult = person("is_adult", period) - pension_age = person("is_SP_age", period) - n_pension_age = benunit.sum(adult & pension_age) - return ( - benunit("is_couple", period) - & (n_pension_age > 0) - & (n_pension_age < benunit.sum(adult)) + # The claimant and partner: adults other than a child or qualifying + # young person for Pension Credit, so a pensioner with an 18 or 19 + # year old dependant in education is not a couple here. + claimant_or_partner = person("is_adult", period) & ~person( + "is_child_or_qualifying_young_person_for_pension_credit", period ) + pension_age = person("is_SP_age", period) + n_pension_age = benunit.sum(claimant_or_partner & pension_age) + return (benunit.sum(claimant_or_partner) == 2) & (n_pension_age == 1) diff --git a/policyengine_uk/variables/gov/dwp/universal_credit/is_uc_eligible.py b/policyengine_uk/variables/gov/dwp/universal_credit/is_uc_eligible.py index de18f6d4ea..69e868d59f 100644 --- a/policyengine_uk/variables/gov/dwp/universal_credit/is_uc_eligible.py +++ b/policyengine_uk/variables/gov/dwp/universal_credit/is_uc_eligible.py @@ -17,9 +17,13 @@ def formula(benunit, period, parameters): capital = benunit("uc_assessable_capital", period) limit = parameters(period).gov.dwp.universal_credit.means_test.capital.limit has_working_age_adult = benunit.any(benunit.members("is_WA_adult", period)) - # A family on the Pension Credit route cannot also have Universal - # Credit (UC (Transitional Provisions) Regs 2014 reg 5(1)(d)). This - # sends mixed-age couples keeping the SI 2019/37 saving, and every - # mixed-age couple before 15 May 2019, to Pension Credit. + # No family gets both Pension Credit and Universal Credit (UC + # (Transitional Provisions) Regs 2014 reg 5(1)(d)). A mixed-age couple + # keeping the SI 2019/37 saving could still choose Universal Credit + # jointly (UC Regs 2013 reg 3(2)(a)) and lose the saving; the model + # keeps it on the Pension Credit route, anchored to its reported + # Pension Credit or Housing Benefit. That, and routing mixed-age + # couples not reported on Universal Credit to Pension Credit before + # 15 May 2019, are modelling choices. pension_credit_route = benunit("meets_pension_credit_age_conditions", period) return has_working_age_adult & ~pension_credit_route & (capital <= limit) From 94231204e2f241a09869a19e220786b8a788f27a Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 2 Oct 2026 15:26:11 -0400 Subject: [PATCH 3/4] Infer the mixed-age saving from the claimant and partner only; fix receipt docs The saving belongs to the couple (SI 2019/37 art. 4(1)), so its default inference now reads only the claimant's and partner's ages and reported awards. A grandparent in the same benefit unit no longer supplies the 1954 age evidence or a Pension Credit or Housing Benefit report. Two YAML cases fail without the change. in_receipt_of_guarantee_credit's documentation no longer says the saving is omitted. Addresses the delta review of cf691ed8 (findings 1 and 3). Co-Authored-By: Claude Opus 5.5 --- .../dwp/pension_credit/mixed_age_couples.yaml | 59 +++++++++++++++++++ .../in_receipt_of_guarantee_credit.py | 8 +-- ..._mixed_age_couple_pension_credit_saving.py | 17 ++++-- 3 files changed, 76 insertions(+), 8 deletions(-) diff --git a/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/mixed_age_couples.yaml b/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/mixed_age_couples.yaml index 6d19157161..cc3018f6c7 100644 --- a/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/mixed_age_couples.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/mixed_age_couples.yaml @@ -519,3 +519,62 @@ meets_pension_credit_age_conditions: false is_pension_credit_eligible: false is_uc_eligible: true + +- name: A grandparent outside the couple does not supply the saving's age evidence + # The benefit unit's claimant and partner are 70 and 60; the 70-year-old was + # born in 1956, after the qualifying date. A 90-year-old grandparent in the + # same benefit unit is not the claimant or partner, so their age cannot meet + # SI 2019/37 art. 4(1). + period: 2026 + absolute_error_margin: 0.01 + input: + people: + grandparent: + age: 90 + is_claimant_or_partner: false + housing_benefit_reported: 5_000 + claimant: + age: 70 + is_claimant_or_partner: true + state_pension: 9_000 + pension_credit_reported: 1_000 + partner: + age: 60 + is_claimant_or_partner: true + benunits: + benunit: + members: [grandparent, claimant, partner] + households: + household: + members: [grandparent, claimant, partner] + output: + is_mixed_age_couple: true + has_mixed_age_couple_pension_credit_saving: false + +- name: A grandparent's reported Pension Credit does not supply the couple's saving + # The claimant (75, born 1951) and partner (60) report nothing; only the + # grandparent reports Pension Credit, which is not the couple's award. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + grandparent: + age: 92 + is_claimant_or_partner: false + pension_credit_reported: 1_000 + claimant: + age: 75 + is_claimant_or_partner: true + state_pension: 9_000 + partner: + age: 60 + is_claimant_or_partner: true + benunits: + benunit: + members: [grandparent, claimant, partner] + households: + household: + members: [grandparent, claimant, partner] + output: + is_mixed_age_couple: true + has_mixed_age_couple_pension_credit_saving: false diff --git a/policyengine_uk/variables/gov/dwp/pension_credit/guarantee_credit/in_receipt_of_guarantee_credit.py b/policyengine_uk/variables/gov/dwp/pension_credit/guarantee_credit/in_receipt_of_guarantee_credit.py index 877ab3606b..1127e6753d 100644 --- a/policyengine_uk/variables/gov/dwp/pension_credit/guarantee_credit/in_receipt_of_guarantee_credit.py +++ b/policyengine_uk/variables/gov/dwp/pension_credit/guarantee_credit/in_receipt_of_guarantee_credit.py @@ -9,10 +9,10 @@ class in_receipt_of_guarantee_credit(Variable): "claims it, and its Guarantee Credit is positive. A Guarantee Credit " "computed for a family that does not claim Pension Credit, or that the " "model does not treat as eligible for it (for example a working-age " - "family), is not received. The model's Pension Credit eligibility " - "omits the SI 2019/37 article 4 saving, so a mixed-age couple it saves " - "(entitled to Pension Credit or Housing Benefit as that couple on 14 " - "May 2019, and to either ever since) is not treated as in receipt. Under " + "family), is not received. A mixed-age couple that keeps Pension " + "Credit under the SI 2019/37 article 4 saving is eligible " + "(meets_pension_credit_age_conditions), so it is in receipt when it " + "claims and its Guarantee Credit is positive. Under " "the Pension Credit freeze the baseline receipt is kept, because the " "frozen award is the baseline award." ) diff --git a/policyengine_uk/variables/gov/dwp/pension_credit/mixed_age_couples/has_mixed_age_couple_pension_credit_saving.py b/policyengine_uk/variables/gov/dwp/pension_credit/mixed_age_couples/has_mixed_age_couple_pension_credit_saving.py index 6ae566b4a5..1f3d816ca3 100644 --- a/policyengine_uk/variables/gov/dwp/pension_credit/mixed_age_couples/has_mixed_age_couple_pension_credit_saving.py +++ b/policyengine_uk/variables/gov/dwp/pension_credit/mixed_age_couples/has_mixed_age_couple_pension_credit_saving.py @@ -30,8 +30,15 @@ class has_mixed_age_couple_pension_credit_saving(Variable): def formula(benunit, period, parameters): p = parameters(period).gov.dwp.pension_credit.mixed_age_couples + person = benunit.members + # Only the claimant and partner's own awards and ages count: the + # saving belongs to the couple (art. 4(1)), not to other members of + # the benefit unit. + claimant_or_partner = person("is_claimant_or_partner", period) + def reported(variables): - return add(benunit, period, variables) > 0 + amount = sum(person(variable, period) for variable in variables) + return benunit.sum(amount * claimant_or_partner) > 0 # Art. 2(3): only Housing Benefit under the pension-age regulations # (SI 2006/214) carries the saving. They apply to a claimant who has @@ -39,10 +46,11 @@ def reported(variables): # pension-age member counts, and not where the couple is on an # income-related legacy benefit, which puts it under the working-age # regulations (reg 5(2)). - person = benunit.members pension_age_member_hb = ( benunit.sum( - person("housing_benefit_reported", period) * person("is_SP_age", period) + person("housing_benefit_reported", period) + * person("is_SP_age", period) + * claimant_or_partner ) > 0 ) @@ -61,7 +69,8 @@ def reported(variables): # 14 May 2019, so its older member had reached the qualifying age by # then. older_member_qualified = benunit.any( - person("is_SP_age", period) + claimant_or_partner + & person("is_SP_age", period) & (person("birth_year", period) <= p.saving_latest_birth_year) ) return ( From 5c212e33a57c567b354ea596cb06b070c4af542b Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 2 Oct 2026 16:40:04 -0400 Subject: [PATCH 4/4] Read only the couple's own Universal Credit report before the exclusion; test each mask Before 15 May 2019 a mixed-age couple reported on Universal Credit stays on it; that test now reads the claimant's and partner's reports, like the saving. The saving's reported-award sums use add_for_members. Two more YAML cases isolate the Housing Benefit mask and the Universal Credit mask (each fails when its mask is removed). The Housing Benefit notebook describes the pension-age route as the code now applies it. Addresses the delta review of 94231204 (findings 5 to 8). Co-Authored-By: Claude Opus 5.5 --- .../programs/gov/dwp/housing-benefit.ipynb | 4 +- .../dwp/pension_credit/mixed_age_couples.yaml | 57 +++++++++++++++++++ .../meets_pension_credit_age_conditions.py | 7 ++- ..._mixed_age_couple_pension_credit_saving.py | 3 +- 4 files changed, 66 insertions(+), 5 deletions(-) diff --git a/docs/book/programs/gov/dwp/housing-benefit.ipynb b/docs/book/programs/gov/dwp/housing-benefit.ipynb index 3fa1f88ec0..01ae7d9a50 100644 --- a/docs/book/programs/gov/dwp/housing-benefit.ipynb +++ b/docs/book/programs/gov/dwp/housing-benefit.ipynb @@ -21,8 +21,8 @@ "\n", "`housing_benefit_eligible` requires the benunit to be either in **social housing** or eligible for the **Local Housing Allowance** rate (broadly, private renters), with assessable capital at or below the working-age (or pension-age) capital limit, and to reach Housing Benefit by one of two routes:\n", "\n", - "- **Pension age**: every adult in the benunit has reached the qualifying age for State Pension Credit (State Pension age). New Housing Benefit claims are open to them ([SI 2014/1230 reg. 6A(4)](https://www.legislation.gov.uk/uksi/2014/1230/regulation/6A)), and Universal Credit is not, so neither a previous claim nor `would_claim_uc` matters.\n", - "- **Continuing award**: any other benunit was **already claiming** Housing Benefit (proxied by a positive `housing_benefit_reported`) and is **not claiming Universal Credit**. Working-age and mixed-age families cannot make new claims; they claim the Universal Credit housing element instead. For mixed-age couples the reported award stands in for the saving for couples who were entitled to Housing Benefit or Pension Credit on 14 May 2019 ([SI 2019/37 art. 4](https://www.legislation.gov.uk/uksi/2019/37/article/4)).\n", + "- **Pension age**: the claimant and any partner have reached the qualifying age for State Pension Credit (State Pension age), or the family is a mixed-age couple that keeps the pension-age route: one entitled to Pension Credit or pension-age Housing Benefit on 14 May 2019 and ever since ([SI 2019/37 art. 4](https://www.legislation.gov.uk/uksi/2019/37/article/4)), or any mixed-age couple not reported on Universal Credit before 15 May 2019 (`meets_pension_credit_age_conditions`). New Housing Benefit claims are open to them ([SI 2014/1230 reg. 6A(4) and (5)](https://www.legislation.gov.uk/uksi/2014/1230/regulation/6A)), and Universal Credit is not, so neither a previous claim nor `would_claim_uc` matters.\n", + "- **Continuing award**: any other benunit was **already claiming** Housing Benefit (proxied by a positive `housing_benefit_reported`) and is **not claiming Universal Credit**. Working-age families, and mixed-age couples without the saving, cannot make new claims; they claim the Universal Credit housing element instead.\n", "\n", "The pension-age test counts the same benunit members as Universal Credit's working-age test, and the continuing-award route requires not claiming Universal Credit, so no benunit receives both. Working-age awards outside specified or temporary accommodation ended on 1 July 2026 in Great Britain ([SI 2025/1148 art. 7](https://www.legislation.gov.uk/uksi/2025/1148/article/7)); PolicyEngine does not yet model that. Claims for specified or temporary accommodation, which remain open at any age, are not modelled.\n", "\n", diff --git a/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/mixed_age_couples.yaml b/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/mixed_age_couples.yaml index cc3018f6c7..14846b2ead 100644 --- a/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/mixed_age_couples.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/mixed_age_couples.yaml @@ -578,3 +578,60 @@ output: is_mixed_age_couple: true has_mixed_age_couple_pension_credit_saving: false + +- name: A grandparent's reported Housing Benefit does not supply the couple's saving + # The claimant (75, born 1951) is old enough and the couple reports nothing. + # Only the grandparent, who is over State Pension age, reports Housing + # Benefit, and that is not the couple's award (SI 2019/37 art. 2(2)(a)). + period: 2026 + absolute_error_margin: 0.01 + input: + people: + grandparent: + age: 90 + is_claimant_or_partner: false + housing_benefit_reported: 5_000 + claimant: + age: 75 + is_claimant_or_partner: true + state_pension: 9_000 + partner: + age: 60 + is_claimant_or_partner: true + benunits: + benunit: + members: [grandparent, claimant, partner] + households: + household: + members: [grandparent, claimant, partner] + output: + is_mixed_age_couple: true + has_mixed_age_couple_pension_credit_saving: false + +- name: Before the exclusion, a grandparent's Universal Credit does not move the couple onto it + # In model year 2018 a mixed-age couple not reported on Universal Credit + # takes the Pension Credit route. Only the couple's own report counts. + period: 2018 + absolute_error_margin: 0.01 + input: + people: + grandparent: + age: 90 + is_claimant_or_partner: false + universal_credit_reported: 3_000 + claimant: + age: 70 + is_claimant_or_partner: true + state_pension: 7_000 + partner: + age: 55 + is_claimant_or_partner: true + benunits: + benunit: + members: [grandparent, claimant, partner] + households: + household: + members: [grandparent, claimant, partner] + output: + is_mixed_age_couple: true + meets_pension_credit_age_conditions: true diff --git a/policyengine_uk/variables/gov/dwp/pension_credit/meets_pension_credit_age_conditions.py b/policyengine_uk/variables/gov/dwp/pension_credit/meets_pension_credit_age_conditions.py index 9542edeeb7..1df5294698 100644 --- a/policyengine_uk/variables/gov/dwp/pension_credit/meets_pension_credit_age_conditions.py +++ b/policyengine_uk/variables/gov/dwp/pension_credit/meets_pension_credit_age_conditions.py @@ -40,7 +40,12 @@ def formula(benunit, period, parameters): # Credit or Universal Credit jointly (UC Regs 2013 reg 3(2)(a)); a # couple reported on Universal Credit stays on it, and any other takes # the Pension Credit route. This is a modelling choice. - reports_uc = add(benunit, period, ["universal_credit_reported"]) > 0 + reports_uc = ( + add_for_members( + benunit, period, ["universal_credit_reported"], claimant_or_partner + ) + > 0 + ) before_exclusion = np.logical_not(excluded) & ~reports_uc mixed_age_route = benunit("is_mixed_age_couple", period) & ( before_exclusion | saving diff --git a/policyengine_uk/variables/gov/dwp/pension_credit/mixed_age_couples/has_mixed_age_couple_pension_credit_saving.py b/policyengine_uk/variables/gov/dwp/pension_credit/mixed_age_couples/has_mixed_age_couple_pension_credit_saving.py index 1f3d816ca3..57b3d9b4e7 100644 --- a/policyengine_uk/variables/gov/dwp/pension_credit/mixed_age_couples/has_mixed_age_couple_pension_credit_saving.py +++ b/policyengine_uk/variables/gov/dwp/pension_credit/mixed_age_couples/has_mixed_age_couple_pension_credit_saving.py @@ -37,8 +37,7 @@ def formula(benunit, period, parameters): claimant_or_partner = person("is_claimant_or_partner", period) def reported(variables): - amount = sum(person(variable, period) for variable in variables) - return benunit.sum(amount * claimant_or_partner) > 0 + return add_for_members(benunit, period, variables, claimant_or_partner) > 0 # Art. 2(3): only Housing Benefit under the pension-age regulations # (SI 2006/214) carries the saving. They apply to a claimant who has