diff --git a/changelog.d/legacy-award-reader-switches-1944-2000-1908-1940.fixed.md b/changelog.d/legacy-award-reader-switches-1944-2000-1908-1940.fixed.md new file mode 100644 index 0000000000..e3e6f0500a --- /dev/null +++ b/changelog.d/legacy-award-reader-switches-1944-2000-1908-1940.fixed.md @@ -0,0 +1,3 @@ +- Count only the parent's and partner's own income-related ESA in the extended childcare parent and partner conditions (SI 2022/1134 regs 11A(1)(e), 14(4) and 15(4)): another member of the benefit unit with an award of their own no longer lets a non-working parent or partner meet them. +- Add tests that the choice between the working-age and pension-age Housing Benefit regulations (HB Regs 2006 reg 5(1)(b)) reads only the claimant's and partner's Income Support, income-based JSA and income-related ESA, as it already does. +- Add tests that the mixed-age couple Pension Credit saving (SI 2019/37) reads only the couple's own Income Support, JSA and ESA reports, as it already does. diff --git a/policyengine_uk/parameters/gov/dfe/extended_childcare_entitlement/disability_criteria.yaml b/policyengine_uk/parameters/gov/dfe/extended_childcare_entitlement/disability_criteria.yaml index b8e1b7da16..a4d7eedbfa 100644 --- a/policyengine_uk/parameters/gov/dfe/extended_childcare_entitlement/disability_criteria.yaml +++ b/policyengine_uk/parameters/gov/dfe/extended_childcare_entitlement/disability_criteria.yaml @@ -25,13 +25,16 @@ values: # SI 2022/1134 reg 14(4)(b) and the specified benefits in reg 14(5) as made, # moved to reg 11A from 30 March 2023 by SI 2023/276. Regs 14(4) and 15(4) ask # whether a person is entitled to a specified benefit, so an allowance reduced - # to nil by an overlapping benefit still counts. + # to nil by an overlapping benefit still counts. Income-related ESA is the + # claimant's and partner's award (claimant_or_partner_esa_income): another + # member of the benefit unit with an award of their own is not the parent or + # partner, so their award does not count. 2022-12-01: - uc_limited_capability_for_WRA # 14(4)(b)(i)-(ii): limited capability for work, or for work and work-related activity - is_entitled_to_carer_benefit # 11A(1)(a)-(b): carer's allowance, or carer's assistance under the Social Security (Scotland) Act 2018 s.28 - receives_uc_carer_element # 11A(1)(c): the carer element under UC Regs reg 29, on an award (reg 14(5)(a) as made: "an award of universal credit [...] that includes the carer element") - receives_limited_capability_for_work_credits # 11A(1)(d): credits for incapacity for work or limited capability for work - esa_contrib # 11A(1)(e): employment and support allowance (contribution-based) - - esa_income # 11A(1)(e): employment and support allowance (income-related) + - claimant_or_partner_esa_income # 11A(1)(e): employment and support allowance (income-related) - incapacity_benefit # 11A(1)(f)-(g): long-term, short-term and transitional incapacity benefit - sda # 11A(1)(h): severe disablement allowance diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/legacy_award_readers/extended_childcare_entitlement.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/legacy_award_readers/extended_childcare_entitlement.yaml new file mode 100644 index 0000000000..54a89f9b4d --- /dev/null +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/legacy_award_readers/extended_childcare_entitlement.yaml @@ -0,0 +1,168 @@ +# SI 2022/1134 reg 15(4)(c): the partner of a parent who meets reg 14(3) +# meets the partner condition, without working, if they are "entitled to a +# specified benefit" (reg 14(4)(b)(iii) likewise for the parent). Reg +# 11A(1)(e) lists employment and support allowance. The model +# reads income-related ESA as the claimant's and partner's award +# (claimant_or_partner_esa_income), which counts for both members of the +# couple. "other" is a member who is neither the claimant, the partner nor a +# child or young person they are responsible for, so an award they report is +# their own claim and does not make the partner entitled to a specified +# benefit. In each case the parent works and meets the income requirements, +# the partner does not work, and the child is three. + +- name: Another member's income-related ESA does not let a non-working partner meet the extended childcare partner condition + period: 2025 + input: + people: + parent: + age: 35 + is_parent: true + is_claimant_or_partner: true + in_work: true + employment_income: 30_000 + extended_childcare_entitlement_meets_income_requirements: true + partner: + age: 34 + is_parent: true + is_claimant_or_partner: true + in_work: false + extended_childcare_entitlement_meets_income_requirements: false + child: + age: 3 + is_claimant_or_partner: false + other: + age: 25 + is_claimant_or_partner: false + current_education: NOT_IN_EDUCATION + esa_income_reported: 5_000 + benunits: + benunit: + members: [parent, partner, child, other] + claims_all_entitled_benefits: false + would_claim_uc: false + households: + household: + members: [parent, partner, child, other] + country: ENGLAND + output: + esa_income: 5_000 + claimant_or_partner_esa_income: 0 + extended_childcare_entitlement_limited_capability_or_specified_benefit: [false, false, false, false] + extended_childcare_entitlement_work_condition: [true, false, false, false] + extended_childcare_entitlement_eligible: false + +- name: Another member's income-related ESA does not let a non-working partner meet the condition in 2023 + period: 2023 + input: + people: + parent: + age: 35 + is_parent: true + is_claimant_or_partner: true + in_work: true + employment_income: 30_000 + extended_childcare_entitlement_meets_income_requirements: true + partner: + age: 34 + is_parent: true + is_claimant_or_partner: true + in_work: false + extended_childcare_entitlement_meets_income_requirements: false + child: + age: 3 + is_claimant_or_partner: false + other: + age: 40 + is_claimant_or_partner: false + current_education: NOT_IN_EDUCATION + esa_income_reported: 4_000 + benunits: + benunit: + members: [parent, partner, child, other] + claims_all_entitled_benefits: false + would_claim_uc: false + households: + household: + members: [parent, partner, child, other] + country: ENGLAND + output: + esa_income: 4_000 + claimant_or_partner_esa_income: 0 + extended_childcare_entitlement_work_condition: [true, false, false, false] + extended_childcare_entitlement_eligible: false + +- name: The partner's own income-related ESA lets the non-working partner meet the extended childcare partner condition + period: 2025 + input: + people: + parent: + age: 35 + is_parent: true + is_claimant_or_partner: true + in_work: true + employment_income: 30_000 + extended_childcare_entitlement_meets_income_requirements: true + partner: + age: 34 + is_parent: true + is_claimant_or_partner: true + in_work: false + extended_childcare_entitlement_meets_income_requirements: false + esa_income_reported: 5_000 + child: + age: 3 + is_claimant_or_partner: false + benunits: + benunit: + members: [parent, partner, child] + claims_all_entitled_benefits: false + would_claim_uc: false + households: + household: + members: [parent, partner, child] + country: ENGLAND + output: + claimant_or_partner_esa_income: 5_000 + extended_childcare_entitlement_work_condition: [true, true, false] + extended_childcare_entitlement_eligible: true + +- name: The partner's own income-related ESA still counts when another member also reports an award + period: 2025 + input: + people: + parent: + age: 35 + is_parent: true + is_claimant_or_partner: true + in_work: true + employment_income: 30_000 + extended_childcare_entitlement_meets_income_requirements: true + partner: + age: 34 + is_parent: true + is_claimant_or_partner: true + in_work: false + extended_childcare_entitlement_meets_income_requirements: false + esa_income_reported: 5_000 + child: + age: 3 + is_claimant_or_partner: false + other: + age: 25 + is_claimant_or_partner: false + current_education: NOT_IN_EDUCATION + esa_income_reported: 5_000 + benunits: + benunit: + members: [parent, partner, child, other] + claims_all_entitled_benefits: false + would_claim_uc: false + households: + household: + members: [parent, partner, child, other] + country: ENGLAND + output: + esa_income: 10_000 + claimant_or_partner_esa_income: 5_000 + extended_childcare_entitlement_work_condition: [true, true, false, false] + extended_childcare_entitlement_eligible: true diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/legacy_award_readers/housing_benefit_pension_age_regulations.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/legacy_award_readers/housing_benefit_pension_age_regulations.yaml new file mode 100644 index 0000000000..86273eb805 --- /dev/null +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/legacy_award_readers/housing_benefit_pension_age_regulations.yaml @@ -0,0 +1,100 @@ +# HB Regs 2006 reg 5(1)(b): the working-age regulations apply to a claimant +# who has reached the qualifying age for State Pension Credit only if "he, or +# if he has a partner, his partner" is on Universal Credit, Income Support, +# income-based JSA or income-related ESA. "other" is a member who is neither +# the claimant, the partner nor a child or young person they are responsible +# for, so an award they report is their own claim and leaves the claimant +# under the pension-age regulations. The model stops paying income-based JSA +# from April 2026 (gov.dwp.JSA.income.active), so the JSA cases are in 2025. + +- name: Another member's income-related ESA leaves a pensioner under the pension-age HB regulations + period: 2026 + input: + people: + claimant: + age: 70 + is_claimant_or_partner: true + other: + age: 30 + is_claimant_or_partner: false + current_education: NOT_IN_EDUCATION + esa_income_reported: 5_000 + benunits: + benunit: + members: [claimant, other] + would_claim_uc: false + households: + household: + members: [claimant, other] + output: + esa_income: 5_000 + claimant_or_partner_esa_income: 0 + housing_benefit_pension_age_regulations_apply: true + +- name: Another member's income-based JSA leaves a pensioner under the pension-age HB regulations + period: 2025 + input: + people: + claimant: + age: 70 + is_claimant_or_partner: true + other: + age: 30 + is_claimant_or_partner: false + current_education: NOT_IN_EDUCATION + jsa_income_reported: 4_000 + benunits: + benunit: + members: [claimant, other] + would_claim_uc: false + households: + household: + members: [claimant, other] + output: + jsa_income: 4_000 + claimant_or_partner_jsa_income: 0 + housing_benefit_pension_age_regulations_apply: true + +- name: A younger partner's income-related ESA brings a pensioner under the working-age HB regulations + period: 2026 + input: + people: + claimant: + age: 70 + is_claimant_or_partner: true + partner: + age: 50 + is_claimant_or_partner: true + esa_income_reported: 5_000 + benunits: + benunit: + members: [claimant, partner] + would_claim_uc: false + households: + household: + members: [claimant, partner] + output: + claimant_or_partner_esa_income: 5_000 + housing_benefit_pension_age_regulations_apply: false + +- name: A younger partner's income-based JSA brings a pensioner under the working-age HB regulations + period: 2025 + input: + people: + claimant: + age: 70 + is_claimant_or_partner: true + partner: + age: 50 + is_claimant_or_partner: true + jsa_income_reported: 4_000 + benunits: + benunit: + members: [claimant, partner] + would_claim_uc: false + households: + household: + members: [claimant, partner] + output: + claimant_or_partner_jsa_income: 4_000 + housing_benefit_pension_age_regulations_apply: false diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/legacy_award_readers/mixed_age_couple_pension_credit_saving.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/legacy_award_readers/mixed_age_couple_pension_credit_saving.yaml new file mode 100644 index 0000000000..93921ebd58 --- /dev/null +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/legacy_award_readers/mixed_age_couple_pension_credit_saving.yaml @@ -0,0 +1,106 @@ +# SI 2019/37 arts 2(3) and 4: a mixed-age couple keeps Pension Credit while it +# stays entitled to Pension Credit or to Housing Benefit under the pension-age +# regulations (SI 2006/214). Those regulations do not apply where the claimant +# ("he, or if he has a partner, his partner") is on Income Support, +# income-based JSA or income-related ESA (reg 5(2)). The saving is inferred +# from reported receipt. "other" is a member who is neither the claimant, the +# partner nor a child or young person they are responsible for, so an award +# they report is their own claim and leaves the couple's Housing Benefit under +# the pension-age regulations. is_mixed_age_couple is entered so the cases +# test the award reports alone. The older member, 75 in 2026, was born in 1951 +# and had reached the qualifying age by 14 May 2019. + +- name: Another member's income-related ESA leaves a mixed-age couple's Housing Benefit saving in place + period: 2026 + input: + people: + older: + age: 75 + is_claimant_or_partner: true + housing_benefit_reported: 3_000 + younger: + age: 60 + is_claimant_or_partner: true + other: + age: 30 + is_claimant_or_partner: false + current_education: NOT_IN_EDUCATION + esa_income_reported: 5_000 + benunits: + benunit: + members: [older, younger, other] + is_mixed_age_couple: true + households: + household: + members: [older, younger, other] + output: + has_mixed_age_couple_pension_credit_saving: true + +- name: Another member's Income Support leaves a mixed-age couple's Housing Benefit saving in place + period: 2026 + input: + people: + older: + age: 75 + is_claimant_or_partner: true + housing_benefit_reported: 3_000 + younger: + age: 60 + is_claimant_or_partner: true + other: + age: 30 + is_claimant_or_partner: false + current_education: NOT_IN_EDUCATION + income_support_reported: 4_000 + benunits: + benunit: + members: [older, younger, other] + is_mixed_age_couple: true + households: + household: + members: [older, younger, other] + output: + has_mixed_age_couple_pension_credit_saving: true + +- name: The younger partner's income-related ESA puts the couple under the working-age regulations, so no saving + period: 2026 + input: + people: + older: + age: 75 + is_claimant_or_partner: true + housing_benefit_reported: 3_000 + younger: + age: 60 + is_claimant_or_partner: true + esa_income_reported: 5_000 + benunits: + benunit: + members: [older, younger] + is_mixed_age_couple: true + households: + household: + members: [older, younger] + output: + has_mixed_age_couple_pension_credit_saving: false + +- name: A mixed-age couple reporting pension-age Housing Benefit and no income-related award keeps the saving + period: 2026 + input: + people: + older: + age: 75 + is_claimant_or_partner: true + housing_benefit_reported: 3_000 + younger: + age: 60 + is_claimant_or_partner: true + benunits: + benunit: + members: [older, younger] + is_mixed_age_couple: true + households: + household: + members: [older, younger] + output: + has_mixed_age_couple_pension_credit_saving: true diff --git a/policyengine_uk/tests/test_legacy_award_readers_properties.py b/policyengine_uk/tests/test_legacy_award_readers_properties.py index 7c6ef57d72..281503f15b 100644 --- a/policyengine_uk/tests/test_legacy_award_readers_properties.py +++ b/policyengine_uk/tests/test_legacy_award_readers_properties.py @@ -20,6 +20,11 @@ 71(1)(h)(iii), through reg 61(2)(b) and HB Regs 2006 reg 56(2)(a) (the student is on the award) and (c) (the student's applicable amount would include a disability or severe disability premium). +- Which Housing Benefit regulations apply to a pensioner: HB Regs 2006 reg + 5(1)(b); SI 2006/214 reg 5(2). The mixed-age couple Pension Credit saving: + SI 2019/37 arts 2(3) and 4, through SI 2006/214 reg 5. +- The extended childcare parent and partner conditions: SI 2022/1134 regs + 11A(1)(e), 14(4)(b) and 15(4). A member of the benefit unit who is neither the claimant, the partner nor a child or young person they are responsible for (for example a non-dependent @@ -70,6 +75,8 @@ "targeted_childcare_entitlement_eligible", "would_claim_IS", "income_support_eligible", + "housing_benefit_pension_age_regulations_apply", + "has_mixed_age_couple_pension_credit_saving", ] MEMBER_READERS = [ "is_scp_eligible", @@ -77,6 +84,7 @@ "is_on_income_related_esa", "is_on_income_based_jsa", "is_on_income_support", + "extended_childcare_entitlement_limited_capability_or_specified_benefit", ] AWARDS = st.sampled_from([0, 0, 200, 3_000]) @@ -237,6 +245,207 @@ def test_other_members_awards_never_change_the_readers(drawn): ), (variable, drawn[i]) +# --- Further family shapes (begin) --- +# Some readers only bite for a claimant over state pension age (the Housing +# Benefit regulations that apply, the mixed-age couple saving), for a single +# applicant under 25, or for parents of a young child of whom only one works +# (the extended childcare partner condition). The families above rarely take +# those shapes, so three more properties check every family and member reader +# on them. The claimant and partner seldom report an award themselves, and on +# the savings drawn below the £16,000 capital limit the added member's award +# survives tariff income, so a reader that wrongly counts it changes (£20,000 +# of savings screens income-related ESA and income-based JSA to nil). The +# invariant is about the readers' own scoping: the shapes pay no rent, so +# Universal Credit stays far below the benefit cap. The cap still counts every +# member's award (benefit_cap_reduction reads the benefit-unit totals), so +# with a binding cap another member's award can reach a reader through +# Universal Credit. +PENSION_AGE = 68 +# Whether the pension-age property enters is_mixed_age_couple, so that a +# reader of the couple's award reports is tested on those reports alone. +ENTER_IS_MIXED_AGE_COUPLE = True +AWARD_REPORTS = [ + "esa_income_reported", + "jsa_income_reported", + "income_support_reported", +] + + +@st.composite +def couple_award_reports(draw): + """Usually no award; otherwise £3,000 of one of them.""" + reports = dict.fromkeys(AWARD_REPORTS, 0) + award = draw(st.sampled_from([None] * 4 + AWARD_REPORTS)) + if award is not None: + reports[award] = 3_000 + return reports + + +@st.composite +def other_members_with_awards(draw): + """As other_members, with at least one award of £3,000 or more.""" + awards = { + "esa_income_reported": draw(st.sampled_from([0, 3_000, 5_000])), + "jsa_income_reported": draw(st.sampled_from([0, 3_000, 5_000])), + "income_support_reported": draw(st.sampled_from([0, 3_000, 5_000])), + } + if not any(awards.values()): + awards[draw(st.sampled_from(sorted(awards)))] = 5_000 + return { + "age": draw(st.integers(16, 60)), + "current_education": "NOT_IN_EDUCATION", + **awards, + } + + +@st.composite +def pension_age_families(draw): + """A claimant over state pension age, usually with a partner of working or + pension age (so many couples are mixed-age), and no dependants. Ages are + listed rather than ranged so that both sides of the 14 May 2019 cut-off + for the mixed-age couple saving (born by 1954) are drawn.""" + ages = [ + draw(st.sampled_from([PENSION_AGE, 72, 76, 81])), + draw(st.sampled_from([45, 58, 63, 70, 79])), + ] + adults = [] + for age in ages[: 1 + draw(st.sampled_from([0, 1, 1]))]: + adults.append( + { + "age": age, + "employment_income": draw(st.sampled_from([0, 3_000, 12_000])), + "housing_benefit_reported": draw(st.sampled_from([0, 3_000, 3_000])), + **draw(couple_award_reports()), + } + ) + household = { + "country": draw(st.sampled_from(["ENGLAND", "SCOTLAND", "WALES"])), + "savings": draw(st.sampled_from([0, 7_000, 20_000])), + } + return adults, [], household + + +@st.composite +def young_single_families(draw): + """A single applicant aged 18 to 24 in Scotland or Wales, no dependants.""" + adults = [ + { + "age": draw(st.integers(18, 24)), + "employment_income": draw(st.sampled_from([0, 3_000, 12_000])), + "current_education": "NOT_IN_EDUCATION", + **draw(couple_award_reports()), + } + ] + household = { + "country": draw(st.sampled_from(["SCOTLAND", "WALES"])), + "savings": draw(st.sampled_from([0, 7_000])), + } + return adults, [], household + + +@st.composite +def working_parent_families(draw): + """Parents of a child aged one to four in England. One parent is in + qualifying paid work within the income limits and the other is not, so + the other meets the extended childcare partner condition only through + limited capability for work or a specified benefit (SI 2022/1134 regs + 14(4) and 15(4)).""" + working = { + "age": draw(st.integers(25, 45)), + "is_parent": True, + "in_work": True, + "employment_income": draw(st.sampled_from([20_000, 30_000])), + "extended_childcare_entitlement_meets_income_requirements": True, + **draw(couple_award_reports()), + } + not_working = { + "age": draw(st.integers(25, 45)), + "is_parent": True, + "in_work": False, + "extended_childcare_entitlement_meets_income_requirements": False, + **draw(couple_award_reports()), + } + household = { + "country": "ENGLAND", + "savings": draw(st.sampled_from([0, 7_000, 20_000])), + } + return [working, not_working], [{"age": draw(st.integers(1, 4))}], household + + +def _family_readers_never_change(drawn, enter_is_mixed_age_couple=False): + without = [(*family, None) for family, _ in drawn] + with_other = [(*family, other) for family, other in drawn] + units = without + with_other + inputs = situation(units) + if enter_is_mixed_age_couple: + for i, (adults, _, _, _) in enumerate(units): + pension_age = [a["age"] >= PENSION_AGE for a in adults] + inputs["benunits"][f"b{i}"]["is_mixed_age_couple"] = { + YEAR: len(adults) == 2 and sum(pension_age) == 1 + } + sim = Simulation(situation=inputs) + flags = sim.calculate("is_claimant_or_partner", YEAR) + sizes = [len(a) + len(d) + (o is not None) for a, d, _, o in units] + starts = np.cumsum([0] + sizes[:-1]) + k = len(drawn) + for i in range(k): + assert not flags[starts[k + i] + sizes[k + i] - 1], drawn[i] + for variable in FAMILY_READERS: + values = sim.calculate(variable, YEAR) + for i in range(k): + assert np.isclose(values[i], values[k + i], atol=0.01), ( + variable, + drawn[i], + ) + for variable in MEMBER_READERS: + values = sim.calculate(variable, YEAR) + for i in range(k): + n = sizes[i] + assert np.array_equal( + values[starts[i] : starts[i] + n], + values[starts[k + i] : starts[k + i] + n], + ), (variable, drawn[i]) + + +@SETTINGS +@given( + st.lists( + st.tuples(pension_age_families(), other_members_with_awards()), + min_size=1, + max_size=6, + ) +) +def test_other_members_awards_never_change_the_readers_at_pension_age(drawn): + _family_readers_never_change(drawn, ENTER_IS_MIXED_AGE_COUPLE) + + +@SETTINGS +@given( + st.lists( + st.tuples(young_single_families(), other_members_with_awards()), + min_size=1, + max_size=6, + ) +) +def test_other_members_awards_never_change_the_readers_for_young_singles(drawn): + _family_readers_never_change(drawn) + + +@SETTINGS +@given( + st.lists( + st.tuples(working_parent_families(), other_members_with_awards()), + min_size=1, + max_size=6, + ) +) +def test_other_members_awards_never_change_the_readers_for_working_parents(drawn): + _family_readers_never_change(drawn) + + +# --- Further family shapes (end) --- + + @SETTINGS @given(st.lists(st.tuples(families(), other_members()), min_size=1, max_size=6)) def test_claimant_or_partner_awards_bounded_by_benefit_unit_awards(drawn): diff --git a/policyengine_uk/variables/gov/dfe/extended_childcare_entitlement/conditions/extended_childcare_entitlement_limited_capability_or_specified_benefit.py b/policyengine_uk/variables/gov/dfe/extended_childcare_entitlement/conditions/extended_childcare_entitlement_limited_capability_or_specified_benefit.py index 79846e1c91..4f2c8228ff 100644 --- a/policyengine_uk/variables/gov/dfe/extended_childcare_entitlement/conditions/extended_childcare_entitlement_limited_capability_or_specified_benefit.py +++ b/policyengine_uk/variables/gov/dfe/extended_childcare_entitlement/conditions/extended_childcare_entitlement_limited_capability_or_specified_benefit.py @@ -14,7 +14,10 @@ class extended_childcare_entitlement_limited_capability_or_specified_benefit(Var "parent and partner conditions without the work or income conditions " "when the other meets them. A benefit-unit-level benefit in the list " "(income-related ESA) counts for both members of a couple; the " - "Universal Credit carer element counts for the carer only." + "Universal Credit carer element counts for the carer only. " + "Income-related ESA is read as the claimant's and partner's award " + "(claimant_or_partner_esa_income): another member of the benefit unit " + "with an award of their own claims in their own right." ) definition_period = YEAR reference = (