From bee86d9780b6cb5d93ba6790ac6343fbf2c049e4 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Thu, 1 Oct 2026 14:30:07 -0400 Subject: [PATCH 1/8] Count other families' children and add the foster and overnight-care bedrooms in the LHA size criteria Universal Credit (UC Regs 2013 Sch 4 paras 9-12): the household head's non-dependants' children are in the extended benefit unit and share rooms with the renter's children; foster children are in no one's extended benefit unit; foster parents and adopters with a child placed (para 12(4)-(5)) and renters whose household includes someone with non-resident overnight care (para 12(A1), (3)) get one additional bedroom for each condition (12(9)). Foster parents are excepted from the shared accommodation rate (29(9A)), and armed forces independence payment counts in the para 29(5) exception. Housing Benefit (HB Regs 2006 and HB (SPC) Regs 2006 reg 13D): the children of non-dependants, boarders and lodgers are occupiers (13D(12)); a child placed with the claimant as a foster child or for adoption is not (reg 21(3)); a qualifying parent or carer and a person who requires overnight care give one additional bedroom each (13D(3A)-(3B)) and are not young individuals. New inputs: is_placed_for_adoption, is_approved_foster_parent_without_placement, has_non_resident_overnight_carer. Fixes #2011 Co-Authored-By: Claude Opus 5.5 --- changelog.d/2011.fixed.md | 1 + .../gov/dwp/LHA/overnight_care_benefits.yaml | 19 + ...ared_accommodation_exception_benefits.yaml | 3 + ...lies_children_and_additional_bedrooms.yaml | 598 ++++++++++++++++++ .../family/LHA_young_person_bedroom.yaml | 21 +- ...est_lha_bedroom_young_people_properties.py | 284 +++++++-- .../gov/dwp/LHA_additional_bedrooms.py | 53 ++ .../variables/gov/dwp/LHA_allowed_bedrooms.py | 146 +++-- ...housing_benefit_LHA_additional_bedrooms.py | 44 ++ .../housing_benefit_LHA_allowed_bedrooms.py | 49 +- ...ild_or_young_person_for_legacy_benefits.py | 10 +- ...hild_or_young_person_placed_with_family.py | 42 ++ ...sing_benefit_qualifying_parent_or_carer.py | 37 ++ .../is_housing_benefit_young_individual.py | 26 +- ...red_accommodation_rate_specified_renter.py | 23 +- .../dwp/is_non_dependant_of_household_head.py | 6 +- .../gov/dwp/lha_renter_has_non_dependant.py | 8 +- ...ha_renter_meets_foster_parent_condition.py | 40 ++ .../dwp/meets_lha_overnight_care_condition.py | 34 + .../has_non_resident_overnight_carer.py | 21 + ...pproved_foster_parent_without_placement.py | 22 + .../is_looked_after_by_local_authority.py | 20 +- .../demographic/is_placed_for_adoption.py | 25 + 23 files changed, 1388 insertions(+), 144 deletions(-) create mode 100644 changelog.d/2011.fixed.md create mode 100644 policyengine_uk/parameters/gov/dwp/LHA/overnight_care_benefits.yaml create mode 100644 policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_other_families_children_and_additional_bedrooms.yaml create mode 100644 policyengine_uk/variables/gov/dwp/LHA_additional_bedrooms.py create mode 100644 policyengine_uk/variables/gov/dwp/housing_benefit_LHA_additional_bedrooms.py create mode 100644 policyengine_uk/variables/gov/dwp/is_child_or_young_person_placed_with_family.py create mode 100644 policyengine_uk/variables/gov/dwp/is_housing_benefit_qualifying_parent_or_carer.py create mode 100644 policyengine_uk/variables/gov/dwp/lha_renter_meets_foster_parent_condition.py create mode 100644 policyengine_uk/variables/gov/dwp/meets_lha_overnight_care_condition.py create mode 100644 policyengine_uk/variables/household/demographic/has_non_resident_overnight_carer.py create mode 100644 policyengine_uk/variables/household/demographic/is_approved_foster_parent_without_placement.py create mode 100644 policyengine_uk/variables/household/demographic/is_placed_for_adoption.py diff --git a/changelog.d/2011.fixed.md b/changelog.d/2011.fixed.md new file mode 100644 index 000000000..050a5351d --- /dev/null +++ b/changelog.d/2011.fixed.md @@ -0,0 +1 @@ +- Count the children of the household head's non-dependants (Universal Credit, UC Regs 2013 Sch 4 paras 9-10) and of non-dependants, boarders and lodgers (Housing Benefit, HB Regs 2006 reg 13D(12)) in the household head's LHA size criteria, sharing rooms with the head's own children. Give foster children no bedroom of their own, and foster parents, adopters with a child placed, and households with a non-resident overnight carer an additional bedroom (UC Sch 4 para 12; HB reg 13D(3A)-(3B)), with new inputs `is_placed_for_adoption`, `is_approved_foster_parent_without_placement` and `has_non_resident_overnight_carer`. Except foster parents from the shared accommodation rate (UC para 29(9A); HB "young individual"), and count armed forces independence payment in the UC para 29(5) exception. diff --git a/policyengine_uk/parameters/gov/dwp/LHA/overnight_care_benefits.yaml b/policyengine_uk/parameters/gov/dwp/LHA/overnight_care_benefits.yaml new file mode 100644 index 000000000..4e2353ce1 --- /dev/null +++ b/policyengine_uk/parameters/gov/dwp/LHA/overnight_care_benefits.yaml @@ -0,0 +1,19 @@ +description: Disability benefits whose recipients, if non-resident carers regularly stay overnight to care for them, give the household an additional bedroom in the LHA size criteria. +values: + 2011-04-01: + - attendance_allowance + - armed_forces_independence_payment + - dla_sc_middle_plus + - pip_dl +metadata: + unit: list + label: LHA overnight care qualifying benefits + reference: + - title: Universal Credit Regulations 2013 Sch 4 para 12(3)(a) + href: https://www.legislation.gov.uk/uksi/2013/376/schedule/4/paragraph/12 + - title: Universal Credit Regulations 2013 reg 2, "attendance allowance" (includes armed forces independence payment) + href: https://www.legislation.gov.uk/uksi/2013/376/regulation/2 + - title: Housing Benefit Regulations 2006 reg 2(1), "person who requires overnight care" + href: https://www.legislation.gov.uk/uksi/2006/213/regulation/2 + - title: Housing Benefit (State Pension Credit) Regulations 2006 reg 2(1), "person who requires overnight care" + href: https://www.legislation.gov.uk/uksi/2006/214/regulation/2 diff --git a/policyengine_uk/parameters/gov/dwp/LHA/shared_accommodation_exception_benefits.yaml b/policyengine_uk/parameters/gov/dwp/LHA/shared_accommodation_exception_benefits.yaml index 26f65c249..96241d625 100644 --- a/policyengine_uk/parameters/gov/dwp/LHA/shared_accommodation_exception_benefits.yaml +++ b/policyengine_uk/parameters/gov/dwp/LHA/shared_accommodation_exception_benefits.yaml @@ -2,6 +2,7 @@ description: Disability benefits whose recipients under 35 are excepted from the values: 2013-04-29: - attendance_allowance + - armed_forces_independence_payment - dla_sc_middle_plus - pip_dl metadata: @@ -10,3 +11,5 @@ metadata: reference: - title: Universal Credit Regulations 2013 Sch 4 para 29(5) href: https://www.legislation.gov.uk/uksi/2013/376/schedule/4/paragraph/29 + - title: Universal Credit Regulations 2013 reg 2, "attendance allowance" (includes armed forces independence payment) + href: https://www.legislation.gov.uk/uksi/2013/376/regulation/2 diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_other_families_children_and_additional_bedrooms.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_other_families_children_and_additional_bedrooms.yaml new file mode 100644 index 000000000..0164ea54e --- /dev/null +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_other_families_children_and_additional_bedrooms.yaml @@ -0,0 +1,598 @@ +# Who counts in the LHA size criteria beyond the claimant's own family, and +# the additional bedrooms for foster parents and overnight care. +# +# Universal Credit (UC Regs 2013 Sch 4): the renter's extended benefit unit is +# the renter, the children and qualifying young persons they are responsible +# for, and their non-dependants (para 9(1)). A non-dependant is anyone who +# normally lives with the renter except, among others, a foster child of the +# renter (9(2)(c), 9(3)), a person liable to pay for their occupation on a +# commercial basis such as a lodger (9(2)(d)), and a child or qualifying young +# person no one in the extended benefit unit is responsible for (9(2)(g)). A +# non-dependant's own child is their responsibility (reg 4(2)), so is a +# non-dependant too, and counts as a child in para 10(1)(d)-(f). No one is +# responsible for a child looked after by a local authority (reg 4(6)(a)), +# except a child placed for adoption (reg 4A(1)(c)). Para 12 gives one +# additional bedroom for each of the overnight care condition and the foster +# parent condition (12(9)). +# +# Housing Benefit (HB Regs 2006 and HB (SPC) Regs 2006 reg 13D): one bedroom +# for each category of "occupier", everyone who occupies the dwelling as +# their home except a joint tenant outside the claimant's household (13D(12)), +# so the children of a non-dependant, boarder or lodger count. A child or +# young person placed with the claimant as a foster child or for adoption +# does not occupy the dwelling (reg 21(3)); the claimant is then a +# "qualifying parent or carer" (reg 2(1)) with one additional bedroom +# (13D(3A)(b)), and one more for overnight care (13D(3A)(a), (3B)). +# +# DWP guidance: ADM F3016, F3034, F3111-F3112, F3131-F3138; LHA Guidance +# Manual (April 2014) paras 2.030-2.033, 2.090, 2.093; HB/CTB circular A4/2012 +# paras 36-38 and 44. +# +# Rents of £200 a week (£10,400 a year) sit between the published Maidstone +# one-bedroom (B) and two-bedroom (C) rates (VOA, LHA April 2024, held for +# 2025-26: B £172.60, C £208.27 a week), so where the category is C the rent +# is met in full. + +- name: A non-dependant's child of the opposite sex needs a bedroom of their own + period: 2026 + input: + people: + renter: + age: 48 + is_household_head: true + is_male: false + son: + age: 12 + is_male: true + daughter: + age: 24 + is_male: false + granddaughter: + age: 11 + is_male: false + benunits: + renter_family: + members: [renter, son] + daughter_family: + members: [daughter, granddaughter] + households: + home: + members: [renter, son, daughter, granddaughter] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + is_non_dependant_of_household_head: [false, false, true, true] + # UC: the renter (para 10(1)(a)), the daughter (10(1)(c)), and the son + # and the granddaughter, who are of opposite sexes and over 10 (10(1)(f)): + # 4 bedrooms. The daughter's own entitlement counts her and her child. + LHA_allowed_bedrooms: [4, 2] + LHA_category: [E, C] + # HB: the same four occupiers' categories (reg 13D(3)(a), (b), (e)). + housing_benefit_LHA_allowed_bedrooms: [4, 2] + housing_benefit_LHA_category: [E, C] + +- name: A non-dependant's child shares with the renter's child of the same sex + period: 2026 + input: + people: + renter: + age: 48 + is_household_head: true + is_male: false + son: + age: 12 + is_male: true + daughter: + age: 24 + is_male: false + grandson: + age: 8 + is_male: true + benunits: + renter_family: + members: [renter, son] + daughter_family: + members: [daughter, grandson] + households: + home: + members: [renter, son, daughter, grandson] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + # The son and the grandson share (UC para 10(1)(e); HB reg 13D(3)(c)): + # 3 bedrooms, the same as without the grandson. + LHA_allowed_bedrooms: [3, 2] + housing_benefit_LHA_allowed_bedrooms: [3, 2] + +- name: A non-dependant's two children under 10 share one bedroom + period: 2026 + input: + people: + renter: + age: 55 + is_household_head: true + daughter: + age: 27 + is_male: false + grandson: + age: 6 + is_male: true + granddaughter: + age: 4 + is_male: false + benunits: + renter_family: + members: [renter] + daughter_family: + members: [daughter, grandson, granddaughter] + households: + home: + members: [renter, daughter, grandson, granddaughter] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + # UC: the renter, the daughter (para 10(1)(c)) and the two grandchildren + # under 10 (10(1)(d)): 3 bedrooms, category D. + LHA_allowed_bedrooms: [3, 2] + LHA_category: [D, C] + # HB: reg 13D(3)(a), (b), (d). + housing_benefit_LHA_allowed_bedrooms: [3, 2] + housing_benefit_LHA_category: [D, C] + +- name: A lodger's child counts for Housing Benefit but not Universal Credit + period: 2026 + input: + people: + householder: + age: 60 + is_household_head: true + lodger: + age: 30 + rent_paid_as_lodger: 5_000 + lodgers_child: + age: 5 + benunits: + householder_family: + members: [householder] + lodger_family: + members: [lodger, lodgers_child] + households: + home: + members: [householder, lodger, lodgers_child] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + is_non_dependant_of_household_head: [false, false, false] + # UC: the lodger is liable to pay on a commercial basis (para 9(2)(d)), + # so is not in the householder's extended benefit unit, and the lodger's + # child is excluded by para 9(2)(g): the householder's bedroom only. + LHA_allowed_bedrooms: [1, 2] + # HB: the lodger and the lodger's child occupy the dwelling as their home + # (reg 13D(12); LHA Guidance Manual para 2.030; circular A4/2012 para + # 44): 3 bedrooms. The lodger's own claim counts their own family. + housing_benefit_LHA_allowed_bedrooms: [3, 2] + +- name: A joint tenant's child does not count for the other joint tenant + period: 2026 + input: + people: + tenant_1: + age: 40 + is_household_head: true + tenant_2: + age: 38 + tenant_2_child: + age: 7 + benunits: + family_1: + members: [tenant_1] + family_2: + members: [tenant_2, tenant_2_child] + liable_for_share_of_household_rent: true + households: + home: + members: [tenant_1, tenant_2, tenant_2_child] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + # A joint tenant outside the claimant's household is not an occupier + # (HB reg 13D(12)), nor their household (LHA Guidance Manual paras 2.031 + # and 2.093); under UC they are liable for their occupation (para + # 9(2)(d)). Each joint tenant counts their own family. + LHA_allowed_bedrooms: [1, 2] + housing_benefit_LHA_allowed_bedrooms: [1, 2] + +- name: Foster children have no bedrooms of their own; the foster parent has one additional bedroom + period: 2026 + input: + people: + foster_parent: + age: 45 + is_household_head: true + foster_son: + age: 12 + is_male: true + is_looked_after_by_local_authority: true + foster_daughter: + age: 11 + is_male: false + is_looked_after_by_local_authority: true + benunits: + family: + members: [foster_parent, foster_son, foster_daughter] + households: + home: + members: [foster_parent, foster_son, foster_daughter] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + is_child_or_qualifying_young_person_for_universal_credit: [false, false, false] + is_child_or_young_person_placed_with_family: [false, true, true] + # UC: foster children are in no one's extended benefit unit (paras 9(1), + # 9(2)(c), 9(3); reg 4(6)(a)); the renter is a foster parent with one + # additional bedroom however many children are placed (para 12(4)(a), + # (9)(b); ADM F3138 example 2): 2 bedrooms, category C. + lha_renter_meets_foster_parent_condition: true + LHA_additional_bedrooms: 1 + LHA_allowed_bedrooms: 2 + LHA_category: C + # HB: the foster children do not occupy the dwelling (reg 21(3); LHA + # Guidance Manual para 2.033); the claimant is a qualifying parent or + # carer (reg 2(1)) with one additional bedroom (reg 13D(3A)(b)). + is_housing_benefit_qualifying_parent_or_carer: true + housing_benefit_LHA_additional_bedrooms: 1 + housing_benefit_LHA_allowed_bedrooms: 2 + housing_benefit_LHA_category: C + uc_housing_costs_element: 10_400 + +- name: A couple fostering a child alongside their own child + period: 2026 + input: + people: + parent_1: + age: 38 + is_household_head: true + is_parent: true + parent_2: + age: 36 + is_parent: true + son: + age: 5 + is_male: true + foster_daughter: + age: 3 + is_male: false + is_looked_after_by_local_authority: true + benunits: + family: + members: [parent_1, parent_2, son, foster_daughter] + households: + home: + members: [parent_1, parent_2, son, foster_daughter] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + is_claimant_or_partner: [true, true, false, false] + # UC: the couple, their son (para 10(1)(f)), and the foster parent's + # additional bedroom (para 12(9)(b)): 3 bedrooms. The foster daughter + # does not share with the son as a child of the extended benefit unit. + LHA_allowed_bedrooms: 3 + LHA_category: D + # HB: the couple, the son (reg 13D(3)(e)) and the qualifying parent or + # carer's bedroom (13D(3A)(b)). + housing_benefit_LHA_allowed_bedrooms: 3 + housing_benefit_LHA_category: D + +- name: A single foster parent under 35 is not restricted to the shared accommodation rate + period: 2026 + input: + people: + foster_parent: + age: 28 + is_household_head: true + foster_child: + age: 7 + is_looked_after_by_local_authority: true + benunits: + family: + members: [foster_parent, foster_child] + households: + home: + members: [foster_parent, foster_child] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + # UC: not responsible for the foster child (reg 4(6)(a)), who is not a + # non-dependant (para 9(2)(c)), but excepted as a renter who satisfies + # the foster parent condition (para 29(9A)). + is_responsible_for_child_or_young_person_for_uc_or_housing_benefit: false + lha_renter_has_non_dependant: false + is_lha_shared_accommodation_rate_specified_renter: false + LHA_allowed_bedrooms: 2 + LHA_category: C + # HB: a single claimant under 35, but a qualifying parent or carer is not + # a young individual (reg 2(1)). + is_housing_benefit_young_individual: false + housing_benefit_LHA_allowed_bedrooms: 2 + housing_benefit_LHA_category: C + +- name: An approved foster parent between placements keeps the additional bedroom + period: 2026 + input: + people: + foster_parent: + age: 30 + is_household_head: true + is_approved_foster_parent_without_placement: true + benunits: + family: + members: [foster_parent] + households: + home: + members: [foster_parent] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + # UC Sch 4 para 12(5); HB reg 2(1), "qualifying parent or carer" (b). + lha_renter_meets_foster_parent_condition: true + is_lha_shared_accommodation_rate_specified_renter: false + LHA_allowed_bedrooms: 2 + LHA_category: C + is_housing_benefit_qualifying_parent_or_carer: true + is_housing_benefit_young_individual: false + housing_benefit_LHA_allowed_bedrooms: 2 + housing_benefit_LHA_category: C + uc_housing_costs_element: 10_400 + +- name: A child placed for adoption counts under Universal Credit but not Housing Benefit + period: 2026 + input: + people: + adopter: + age: 40 + is_household_head: true + child: + age: 4 + is_placed_for_adoption: true + benunits: + family: + members: [adopter, child] + households: + home: + members: [adopter, child] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + # UC: the adopter is responsible for the child (reg 4A(1)(c), from 1 + # April 2024), who has a bedroom (para 10(1)(f)), and as an adopter with + # whom a child is placed meets the foster parent condition (para + # 12(4)(b); ADM F3133): 3 bedrooms. + is_child_or_qualifying_young_person_for_universal_credit: [false, true] + lha_renter_meets_foster_parent_condition: true + LHA_allowed_bedrooms: 3 + LHA_category: D + # HB: the child is not a member of the household nor an occupier (reg + # 21(3)(b)-(c)); the adopter is a qualifying parent or carer: 2 bedrooms. + is_child_or_young_person_for_legacy_benefits: [false, false] + is_child_or_young_person_placed_with_family: [false, true] + housing_benefit_LHA_allowed_bedrooms: 2 + housing_benefit_LHA_category: C + +- name: A disabled renter with a non-resident overnight carer has an additional bedroom + period: 2026 + input: + people: + renter: + age: 62 + is_household_head: true + attendance_allowance: 5_000 + has_non_resident_overnight_carer: true + benunits: + family: + members: [renter] + households: + home: + members: [renter] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + # UC Sch 4 para 12(A1)(a), (3) (ADM F3132 example 1); HB reg + # 13D(3A)(a)(i). + meets_lha_overnight_care_condition: true + LHA_additional_bedrooms: 1 + LHA_allowed_bedrooms: 2 + LHA_category: C + housing_benefit_LHA_additional_bedrooms: 1 + housing_benefit_LHA_allowed_bedrooms: 2 + housing_benefit_LHA_category: C + uc_housing_costs_element: 10_400 + +- name: Overnight care from a partner who lives in the home gives no additional bedroom + period: 2026 + input: + people: + renter: + age: 50 + is_household_head: true + pip_dl: 5_000 + partner: + age: 49 + benunits: + couple: + members: [renter, partner] + households: + home: + members: [renter, partner] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + # The carer must not live in the home (UC para 12(3)(b); ADM F3132 + # example 3; HB reg 2(1), "person who requires overnight care" (b)). + meets_lha_overnight_care_condition: [false, false] + LHA_additional_bedrooms: 0 + LHA_allowed_bedrooms: 1 + housing_benefit_LHA_allowed_bedrooms: 1 + +- name: Overnight care for a non-dependant gives the renter an additional bedroom + period: 2026 + input: + people: + renter: + age: 58 + is_household_head: true + son: + age: 30 + pip_dl: 5_000 + has_non_resident_overnight_carer: true + benunits: + renter_family: + members: [renter] + son_family: + members: [son] + households: + home: + members: [renter, son] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + # UC: the son is a non-dependant (para 9(2)), in the renter's extended + # benefit unit, and meets the overnight care condition (para + # 12(A1)(b)): the renter, the son and the carer's room, 3 bedrooms. + LHA_additional_bedrooms: [1, 1] + LHA_allowed_bedrooms: [3, 2] + # HB: an occupier other than the claimant or partner who requires + # overnight care (reg 13D(3A)(a)(iii)). + housing_benefit_LHA_additional_bedrooms: [1, 1] + housing_benefit_LHA_allowed_bedrooms: [3, 2] + +- name: Two people needing overnight care give one additional bedroom + period: 2026 + input: + people: + partner_1: + age: 55 + is_household_head: true + dla_sc_middle_plus: true + has_non_resident_overnight_carer: true + partner_2: + age: 54 + dla_sc_middle_plus: true + has_non_resident_overnight_carer: true + benunits: + couple: + members: [partner_1, partner_2] + households: + home: + members: [partner_1, partner_2] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + # UC para 12(9)(a) (ADM F3138 example 1); HB reg 13D(3A)(a). + LHA_additional_bedrooms: 1 + LHA_allowed_bedrooms: 2 + housing_benefit_LHA_additional_bedrooms: 1 + housing_benefit_LHA_allowed_bedrooms: 2 + +- name: Foster parents one of whom needs overnight care have two additional bedrooms + period: 2026 + input: + people: + parent_1: + age: 44 + is_household_head: true + attendance_allowance: 5_000 + has_non_resident_overnight_carer: true + parent_2: + age: 42 + foster_child_1: + age: 9 + is_looked_after_by_local_authority: true + foster_child_2: + age: 6 + is_looked_after_by_local_authority: true + benunits: + family: + members: [parent_1, parent_2, foster_child_1, foster_child_2] + households: + home: + members: [parent_1, parent_2, foster_child_1, foster_child_2] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + is_claimant_or_partner: [true, true, false, false] + # UC para 12(9)(a)-(b) (ADM F3138 example 2): the couple's bedroom and + # one for each condition, 3 bedrooms. + LHA_additional_bedrooms: 2 + LHA_allowed_bedrooms: 3 + # HB reg 13D(3B): two additional bedrooms where 13D(3A)(a) and (b) both + # apply. + housing_benefit_LHA_additional_bedrooms: 2 + housing_benefit_LHA_allowed_bedrooms: 3 + +- name: A single Housing Benefit claimant under 35 who needs overnight care is not a young individual + period: 2026 + input: + people: + claimant: + age: 25 + is_household_head: true + pip_dl: 5_000 + has_non_resident_overnight_carer: true + benunits: + family: + members: [claimant] + households: + home: + members: [claimant] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + # HB Regs 2006 reg 2(1), "young individual": not one who requires + # overnight care. One bedroom plus the carer's. + is_housing_benefit_young_individual: false + housing_benefit_LHA_allowed_bedrooms: 2 + housing_benefit_LHA_category: C + # UC: excepted from shared accommodation by the daily living component + # (para 29(5)); 2 bedrooms with the carer's. + is_lha_shared_accommodation_rate_specified_renter: false + LHA_allowed_bedrooms: 2 + LHA_category: C + +- name: An armed forces independence payment excepts a renter under 35 from the shared accommodation rate + period: 2026 + input: + people: + renter: + age: 30 + is_household_head: true + armed_forces_independence_payment: 8_000 + benunits: + family: + members: [renter] + households: + home: + members: [renter] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + # UC Sch 4 para 29(5)(b): attendance allowance, which includes armed + # forces independence payment (reg 2). + is_lha_shared_accommodation_rate_specified_renter: false + LHA_category: B diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_young_person_bedroom.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_young_person_bedroom.yaml index d1a3e83f8..16cd81fe7 100644 --- a/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_young_person_bedroom.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_young_person_bedroom.yaml @@ -115,7 +115,7 @@ housing_benefit_LHA_allowed_bedrooms: 2 housing_benefit_LHA_category: C -- name: A qualifying young person no one is responsible for has no Universal Credit bedroom +- name: A looked-after qualifying young person has no Universal Credit bedroom of their own period: 2026 input: people: @@ -141,10 +141,21 @@ output: is_qualifying_young_person_for_universal_credit: [false, true] is_child_or_qualifying_young_person_for_universal_credit: [false, false] - # Not under para 10(1)(b), and not a non-dependant (para 9(2)(g)): the - # renter's bedroom only. - LHA_allowed_bedrooms: 1 - LHA_category: B + # Not under para 10(1)(b), and not a non-dependant (para 9(2)(g)), so no + # bedroom of their own. The carer they are placed with is a foster parent + # (reg 2), so has one additional bedroom (para 12(4)(a), (9)(b)): 2 + # bedrooms, category C. + LHA_additional_bedrooms: 1 + LHA_allowed_bedrooms: 2 + LHA_category: C + # HB: a young person placed with the claimant by a local authority does + # not occupy the dwelling (HB Regs 2006 reg 21(3)), but the claimant is a + # qualifying parent or carer (reg 2(1)) with one additional bedroom (reg + # 13D(3A)(b)): 2 bedrooms. + is_child_or_young_person_placed_with_family: [false, true] + housing_benefit_LHA_additional_bedrooms: 1 + housing_benefit_LHA_allowed_bedrooms: 2 + housing_benefit_LHA_category: C - name: A qualifying young person cannot share with a younger sibling of the same sex period: 2026 diff --git a/policyengine_uk/tests/test_lha_bedroom_young_people_properties.py b/policyengine_uk/tests/test_lha_bedroom_young_people_properties.py index b23fa6a8c..efbec9389 100644 --- a/policyengine_uk/tests/test_lha_bedroom_young_people_properties.py +++ b/policyengine_uk/tests/test_lha_bedroom_young_people_properties.py @@ -1,29 +1,56 @@ -"""Property-based tests for the bedrooms of benefit-unit members aged 16 or -over who are not the claimant or partner (UC Regs 2013 Sch 4 paras 9-10; HB -Regs 2006 and HB (SPC) Regs 2006 reg 13D(3)). +"""Property-based tests for the LHA size criteria (UC Regs 2013 Sch 4 paras +9-12; HB Regs 2006 and HB (SPC) Regs 2006 reg 13D and reg 21(3)): the +bedrooms of benefit-unit members aged 16 or over who are not the claimant or +partner, the children of other families in the household, foster and +adoption placements, and the additional bedrooms for foster parents and +overnight care. Invariants, for any generated population of households: 1. Monotonicity: adding a person aged 16 to 19 to any family never lowers any family's Universal Credit or Housing Benefit bedrooms, whether the claimant and partner are supplied or inferred. -2. Exact effect: when the added person is not the claimant or partner, their - family gains one Housing Benefit bedroom, and one Universal Credit bedroom - unless they are a qualifying young person no one is responsible for (para - 9(2)(g)). The household head's family also gains one bedroom under both - schemes if the person joins a non-dependant's family, and one Housing - Benefit bedroom if they join a boarder's or lodger's family. No other - family's bedrooms change. -3. Reference: every family's bedrooms equal an independent count of the size - criteria: one for the claimant or couple; one for each other member aged - 16 or over (for Universal Credit, except a qualifying young person no one - is responsible for); for the household head's family, one for each person - aged 16 or over in a non-dependant's family (and, for Housing Benefit, in - a boarder's or lodger's family); and the fewest rooms that hold the - family's children under 16 two to a room, where only children of the same - sex or two children under 10 may share, found by brute force. Children of - other families are not counted for the household head, matching the model - (a separate, existing gap). +2. Exact effect of a person aged 16 to 19: when the added person is not the + claimant or partner, their family gains one Housing Benefit bedroom + unless the person is placed with it as a foster child (HB reg 21(3)), and + one Universal Credit bedroom unless they are a qualifying young person no + one is responsible for (para 9(2)(g)); a family they are placed with as a + foster child gains the foster parent's (UC, para 12) or qualifying parent + or carer's (HB, 13D(3A)(b)) bedroom if it did not already have it. The + household head's family also gains one bedroom under both schemes if the + person joins a non-dependant's family (UC: unless no one is responsible + for them), and one Housing Benefit bedroom if they join a boarder's or + lodger's family. No other family's bedrooms change. +3. Children: adding a child under 16 who is neither fostered nor placed for + adoption to any family never lowers any family's bedrooms under either + scheme and raises each by at most one. +4. Foster children: adding a foster child to a family gives that family one + more bedroom under each scheme if it did not already meet the foster + parent condition (UC) or have a qualifying parent or carer (HB), and none + otherwise. No other family's Universal Credit bedrooms change; the + household head's Housing Benefit bedrooms rise by at most one when the + child is placed with an occupier's family, whose children are occupiers. +5. Reference: every family's bedrooms, and its additional bedrooms, equal an + independent count of the size criteria: + - one for the claimant or couple; + - one for each other member aged 16 or over (UC: except a qualifying + young person no one is responsible for; HB: except one placed with the + family as a foster child); + - for the household head's family, one for each person aged 16 or over + in a non-dependant's family (and, for HB, in a boarder's or lodger's + family); + - the fewest rooms that hold the counted children under 16 two to a + room, where only children of the same sex or two children under 10 may + share, found by brute force. UC counts the family's own children and, + for the household head's family, the non-dependants' children, but no + foster child. HB counts the family's own children other than foster + children and children placed for adoption and, for the household + head's family, every child of a non-dependant's, boarder's or lodger's + family; + - one additional bedroom if anyone so counted, or a foster child of the + family, has overnight care, and one if the family fosters, has a child + placed for adoption, or has an approved foster parent between + placements. """ from itertools import combinations @@ -43,16 +70,22 @@ ) ROLES = ["sharer", "boarder", "lodger", "non_dependant"] EDUCATION = ["NOT_IN_EDUCATION", "UPPER_SECONDARY", "TERTIARY"] +KINDS = ["own", "own", "own", "foster", "adopted"] +OVERNIGHT = st.sampled_from([False, False, False, True]) -child = st.tuples(st.integers(0, 15), st.booleans()) # (age, is_male) +# (age, is_male, kind, has overnight care) +child = st.tuples(st.integers(0, 15), st.booleans(), st.sampled_from(KINDS), OVERNIGHT) @st.composite def family(draw, role): return dict( role=role, - adults=draw(st.lists(st.integers(20, 85), min_size=1, max_size=2)), + adults=draw( + st.lists(st.tuples(st.integers(20, 85), OVERNIGHT), min_size=1, max_size=2) + ), children=draw(st.lists(child, min_size=0, max_size=4)), + between_placements=draw(st.sampled_from([False, False, False, True])), ) @@ -87,9 +120,37 @@ def scenario(draw): return population, (h, f), draw(young_person()) -def build(population, added=None, supply_roles=True): - """One situation for the population, optionally with a person added to - family ``added[0]`` = (household, family) with attributes ``added[1]``. +@st.composite +def child_scenario(draw, kinds): + population = draw(st.lists(household(), min_size=1, max_size=4)) + h = draw(st.integers(0, len(population) - 1)) + f = draw(st.integers(0, len(population[h]) - 1)) + added = ( + draw(st.integers(0, 15)), + draw(st.booleans()), + draw(st.sampled_from(kinds)), + False, + ) + return population, (h, f), added + + +def child_inputs(age, male, kind, overnight): + inputs = {"age": age, "is_male": male, "is_household_head": False} + if kind == "foster": + inputs["is_looked_after_by_local_authority"] = True + if kind == "adopted": + inputs["is_placed_for_adoption"] = True + if overnight: + inputs["dla_sc_middle_plus"] = True + inputs["has_non_resident_overnight_carer"] = True + return inputs + + +def build(population, added=None, supply_roles=True, added_child=None): + """One situation for the population, optionally with a person aged 16 to + 19 added to family ``added[0]`` = (household, family) with attributes + ``added[1]``, or a child ``added_child[1]`` = (age, is_male, kind, + overnight) added to family ``added_child[0]``. Returns the situation and, per benefit unit, its (household, family).""" people, benunits, homes, keys = {}, {}, {}, [] @@ -98,17 +159,25 @@ def build(population, added=None, supply_roles=True): for f, fam in enumerate(families): name = f"h{h}_f{f}" ids = [] - for i, age in enumerate(fam["adults"]): + for i, (age, overnight) in enumerate(fam["adults"]): pid = f"{name}_adult_{i}" people[pid] = {"age": age, "is_household_head": False} + if overnight: + people[pid]["dla_sc_middle_plus"] = True + people[pid]["has_non_resident_overnight_carer"] = True if supply_roles: people[pid]["is_claimant_or_partner"] = True elif fam["children"]: people[pid]["is_parent"] = True ids.append(pid) - for i, (age, male) in enumerate(fam["children"]): + if fam["between_placements"]: + people[ids[0]]["is_approved_foster_parent_without_placement"] = True + children = list(fam["children"]) + if added_child is not None and added_child[0] == (h, f): + children.append(added_child[1]) + for i, spec in enumerate(children): pid = f"{name}_child_{i}" - people[pid] = {"age": age, "is_male": male, "is_household_head": False} + people[pid] = child_inputs(*spec) if supply_roles: people[pid]["is_claimant_or_partner"] = False ids.append(pid) @@ -165,6 +234,35 @@ def best(remaining): return best(list(children)) +def fosters(fam): + """Whether the family meets the foster parent condition (UC) or has a + qualifying parent or carer (HB) through its children or adults.""" + return fam["between_placements"] or any( + kind in ("foster", "adopted") for _, _, kind, _ in fam["children"] + ) + + +def flags(sim, situation, pid): + """The added person's attributes as the model determines them.""" + index = list(situation["people"]).index(pid) + + def value(variable): + return bool(sim.calculate(variable, YEAR)[index]) + + qualifying = value("is_qualifying_young_person_for_universal_credit") + responsible = value("is_child_or_qualifying_young_person_for_universal_credit") + return dict( + # A qualifying young person no one is responsible for (para 9(2)(g)). + unclaimed=qualifying and not responsible, + # Placed with the family by a local authority (HB reg 21(3)). + placed=value("is_child_or_young_person_placed_with_family"), + # A child under 18 looked after by a local authority is placed with + # a foster parent (UC Regs 2013 reg 2). + fostered=value("is_looked_after_by_local_authority") + and situation["people"][pid]["age"] < 18, + ) + + @PROPERTY_SETTINGS @given(scenario(), st.booleans()) def test_adding_a_person_aged_16_to_19_never_lowers_bedrooms(case, supply_roles): @@ -187,61 +285,125 @@ def test_exact_effect_of_adding_a_person_aged_16_to_19(case): after, _ = build(population, (target, person)) _, uc_before, hb_before = bedrooms(before) sim, uc_after, hb_after = bedrooms(after) - # Whether the added person is a qualifying young person no one is - # responsible for. (The qualifying young person tests themselves are - # covered elsewhere.) - pid = f"h{target[0]}_f{target[1]}_added" - index = list(after["people"]).index(pid) - qualifying = sim.calculate("is_qualifying_young_person_for_universal_credit", YEAR) - responsible = sim.calculate( - "is_child_or_qualifying_young_person_for_universal_credit", YEAR - ) - unclaimed = bool(qualifying[index]) and not bool(responsible[index]) + added = flags(sim, after, f"h{target[0]}_f{target[1]}_added") + fam = population[target[0]][target[1]] # 2. Exact effect. expected_uc = np.zeros(len(keys)) expected_hb = np.zeros(len(keys)) t = keys.index(target) - expected_uc[t] += 0 if unclaimed else 1 - expected_hb[t] += 1 - role = population[target[0]][target[1]]["role"] + expected_uc[t] += 0 if added["unclaimed"] else 1 + expected_uc[t] += int(added["fostered"] and not fosters(fam)) + expected_hb[t] += 0 if added["placed"] else 1 + expected_hb[t] += int(added["placed"] and not fosters(fam)) head = keys.index((target[0], 0)) - if role == "non_dependant": - expected_uc[head] += 1 + if fam["role"] == "non_dependant": + expected_uc[head] += 0 if added["unclaimed"] else 1 expected_hb[head] += 1 - elif role in ("boarder", "lodger"): + elif fam["role"] in ("boarder", "lodger"): expected_hb[head] += 1 assert np.array_equal(uc_after - uc_before, expected_uc) assert np.array_equal(hb_after - hb_before, expected_hb) +@PROPERTY_SETTINGS +@given(child_scenario(["own"])) +def test_adding_a_child_raises_each_family_by_at_most_one_bedroom(case): + population, target, added_child = case + before, keys = build(population) + after, _ = build(population, added_child=(target, added_child)) + _, uc_before, hb_before = bedrooms(before) + _, uc_after, hb_after = bedrooms(after) + # 3. Children. + for change in (uc_after - uc_before, hb_after - hb_before): + assert np.all((change == 0) | (change == 1)) + + +@PROPERTY_SETTINGS +@given(child_scenario(["foster"])) +def test_a_foster_child_adds_only_the_foster_parents_bedroom(case): + population, target, added_child = case + before, keys = build(population) + after, _ = build(population, added_child=(target, added_child)) + _, uc_before, hb_before = bedrooms(before) + _, uc_after, hb_after = bedrooms(after) + # 4. Foster children. + fam = population[target[0]][target[1]] + t = keys.index(target) + new_carer = int(not fosters(fam)) + expected_uc = np.zeros(len(keys)) + expected_uc[t] = new_carer + assert np.array_equal(uc_after - uc_before, expected_uc) + hb_change = hb_after - hb_before + assert hb_change[t] == new_carer + head = keys.index((target[0], 0)) + for b in range(len(keys)): + if b == t: + continue + if b == head and fam["role"] in ("non_dependant", "boarder", "lodger"): + assert hb_change[b] in (0, 1) + else: + assert hb_change[b] == 0 + + @PROPERTY_SETTINGS @given(scenario()) def test_bedrooms_match_an_independent_count_of_the_size_criteria(case): population, target, person = case situation, keys = build(population, (target, person)) sim, uc, hb = bedrooms(situation) - qualifying = sim.calculate("is_qualifying_young_person_for_universal_credit", YEAR) - responsible = sim.calculate( - "is_child_or_qualifying_young_person_for_universal_credit", YEAR - ) - unclaimed = dict( - zip(situation["people"], np.asarray(qualifying) & ~np.asarray(responsible)) + uc_additional = np.asarray(sim.calculate("LHA_additional_bedrooms", YEAR)) + hb_additional = np.asarray( + sim.calculate("housing_benefit_LHA_additional_bedrooms", YEAR) ) - # 3. Reference count. + added = flags(sim, situation, f"h{target[0]}_f{target[1]}_added") + # 5. Reference count. for b, (h, f) in enumerate(keys): families = population[h] fam = families[f] - added = (h, f) == target - own_children = fewest_rooms_for_children(fam["children"]) - own_uc = int(added and not unclaimed[f"h{h}_f{f}_added"]) - own_hb = int(added) - outside_uc = outside_hb = 0 + is_target = (h, f) == target + # Own members aged 16 or over who are not the claimant or partner. + uc_rooms = 1 + int(is_target and not added["unclaimed"]) + hb_rooms = 1 + int(is_target and not added["placed"]) + # Children: UC counts the children the family is responsible for + # (not foster children); HB counts occupiers (not children placed + # with the family as foster children or for adoption). + uc_children = [c for c in fam["children"] if c[2] != "foster"] + hb_children = [c for c in fam["children"] if c[2] == "own"] + # Overnight care: the family's own members, including a foster + # child (UC para 12(A1)(c); HB 13D(3A)(a)(iv)). + uc_overnight = hb_overnight = any(o for _, o in fam["adults"]) or any( + c[3] for c in fam["children"] + ) + uc_foster = fosters(fam) or (is_target and added["fostered"]) + hb_carer = fosters(fam) or (is_target and added["placed"]) if fam["role"] == "head": for g, other in enumerate(families[1:], start=1): - aged_16_or_over = len(other["adults"]) + int(target == (h, g)) + joins = target == (h, g) if other["role"] == "non_dependant": - outside_uc += aged_16_or_over + uc_rooms += len(other["adults"]) + int( + joins and not added["unclaimed"] + ) + uc_children += [c for c in other["children"] if c[2] != "foster"] + uc_overnight |= any(o for _, o in other["adults"]) or any( + c[3] for c in other["children"] if c[2] != "foster" + ) if other["role"] in ("non_dependant", "boarder", "lodger"): - outside_hb += aged_16_or_over - assert uc[b] == 1 + own_uc + outside_uc + own_children - assert hb[b] == 1 + own_hb + outside_hb + own_children + hb_rooms += len(other["adults"]) + int(joins) + hb_children += list(other["children"]) + hb_overnight |= any(o for _, o in other["adults"]) or any( + c[3] for c in other["children"] + ) + expected_uc_additional = int(uc_overnight) + int(uc_foster) + expected_hb_additional = int(hb_overnight) + int(hb_carer) + assert uc_additional[b] == expected_uc_additional + assert hb_additional[b] == expected_hb_additional + assert uc[b] == ( + uc_rooms + + fewest_rooms_for_children([c[:2] for c in uc_children]) + + expected_uc_additional + ) + assert hb[b] == ( + hb_rooms + + fewest_rooms_for_children([c[:2] for c in hb_children]) + + expected_hb_additional + ) diff --git a/policyengine_uk/variables/gov/dwp/LHA_additional_bedrooms.py b/policyengine_uk/variables/gov/dwp/LHA_additional_bedrooms.py new file mode 100644 index 000000000..6a9dab2c1 --- /dev/null +++ b/policyengine_uk/variables/gov/dwp/LHA_additional_bedrooms.py @@ -0,0 +1,53 @@ +from policyengine_uk.model_api import * + + +class LHA_additional_bedrooms(Variable): + value_type = float + entity = BenUnit + label = "Additional bedrooms in the Universal Credit size criteria" + documentation = ( + "One additional bedroom if anyone in the renter's extended benefit " + "unit, or a foster child of the renter, meets the overnight care " + "condition (see meets_lha_overnight_care_condition), however many " + "people do; and one if the renter or a joint renter meets the foster " + "parent condition (see lha_renter_meets_foster_parent_condition), " + "however many children are placed. The extended benefit unit " + "includes the household head's non-dependants and their children. " + "The disabled child and disabled person conditions, for children or " + "couples who cannot share a bedroom, are not modelled." + ) + definition_period = YEAR + reference = ( + "https://www.legislation.gov.uk/uksi/2013/376/schedule/4/paragraph/9", + "https://www.legislation.gov.uk/uksi/2013/376/schedule/4/paragraph/10", + "https://www.legislation.gov.uk/uksi/2013/376/schedule/4/paragraph/12", + ) + + def formula(benunit, period, parameters): + person = benunit.members + overnight_care = person("meets_lha_overnight_care_condition", period) + responsible = person( + "is_child_or_qualifying_young_person_for_universal_credit", period + ) + child = person("is_child_for_universal_credit", period) + no_one_responsible = ( + child | person("is_qualifying_young_person_for_universal_credit", period) + ) & ~responsible + # UC Regs 2013 Sch 4 para 12(A1)(a)-(b): the renter and the members of + # their extended benefit unit, which excludes a child or qualifying + # young person no one is responsible for (paras 9(1) and 9(2)(g)); + # (c): a child for whom the renter meets the foster parent condition. + own = overnight_care & ~(no_one_responsible & ~child) + # Para 9(1)(c): the household head's non-dependants from other + # families, and their children. + other = ( + overnight_care + & person("is_non_dependant_of_household_head", period) + & ~no_one_responsible + ) + head_family = benunit.any(person("is_household_head", period)) + others = head_family * benunit.max(person.household.sum(other)) + # Para 12(9)(a)-(b): one bedroom for each condition met. + overnight_room = benunit.any(own) | (others > 0) + foster_room = benunit("lha_renter_meets_foster_parent_condition", period) + return 1.0 * overnight_room + 1.0 * foster_room diff --git a/policyengine_uk/variables/gov/dwp/LHA_allowed_bedrooms.py b/policyengine_uk/variables/gov/dwp/LHA_allowed_bedrooms.py index 4f91b4975..a89c37115 100644 --- a/policyengine_uk/variables/gov/dwp/LHA_allowed_bedrooms.py +++ b/policyengine_uk/variables/gov/dwp/LHA_allowed_bedrooms.py @@ -6,28 +6,18 @@ warnings.filterwarnings("ignore") -def bedrooms_for_children(benunit, period): - """Bedrooms for the family's children under 16. +def rooms_for_children(boys_under_10, older_boys, girls_under_10, older_girls): + """The fewest bedrooms that hold children two to a room, where two + children may share if they are of the same sex or both under 10. - Children must share rooms in pairs unless they are opposite-sex and one - is 10 or over. This is the minimum number of bedrooms that allocates them - under those rules. + The arguments count children under 16: boys and girls under 10, and boys + and girls aged 10 to 15. """ - person = benunit.members - age = person("age", period) - male = person("is_male", period) - under_16 = age < 16 - under_10 = age < 10 - child_over_10 = ~under_10 & under_16 - boys_under_10 = benunit.sum(under_10 & male) - boys_over_10 = benunit.sum(child_over_10 & male) - girls_under_10 = benunit.sum(under_10 & ~male) - girls_over_10 = benunit.sum(child_over_10 & ~male) # First, have over-10s share where possible - over_10_rooms = (boys_over_10 + 1) // 2 + (girls_over_10 + 1) // 2 + over_10_rooms = (older_boys + 1) // 2 + (older_girls + 1) // 2 # There may children over 10 still not sharing - space_for_boy_under_10 = boys_over_10 % 2 - space_for_girl_under_10 = girls_over_10 % 2 + space_for_boy_under_10 = older_boys % 2 + space_for_girl_under_10 = older_girls % 2 # Have those spaces filled where possible by children under 10 left_over_boys_under_10 = max_(boys_under_10 - space_for_boy_under_10, 0) left_over_girls_under_10 = max_(girls_under_10 - space_for_girl_under_10, 0) @@ -36,29 +26,76 @@ def bedrooms_for_children(benunit, period): return over_10_rooms + under_10_rooms +def bedrooms_for_children(benunit, period, own_child=None, other_child=None): + """Bedrooms for the children under 16 in the family's size criteria. + + Children must share rooms in pairs unless they are opposite-sex and one + is 10 or over. This is the minimum number of bedrooms that allocates them + under those rules. + + ``own_child`` marks the family's members counted as its children (by + default, every member under 16). ``other_child`` marks people under 16 in + other families of the household who count in the household head's + family's size criteria, such as a non-dependant's child; they share rooms + with the head family's own children. + """ + person = benunit.members + age = person("age", period) + male = person("is_male", period) + under_16 = age < 16 + under_10 = age < 10 + if own_child is None: + own_child = under_16 + own_child = own_child & under_16 + head_family = benunit.any(person("is_household_head", period)) + + def count(group): + own = benunit.sum(own_child & group) + if other_child is None: + return own + others = person.household.sum(other_child & under_16 & group) + return own + head_family * benunit.max(others) + + return rooms_for_children( + count(under_10 & male), + count(~under_10 & male), + count(under_10 & ~male), + count(~under_10 & ~male), + ) + + class LHA_allowed_bedrooms(Variable): value_type = float entity = BenUnit label = "The number of bedrooms covered by LHA for the benefit unit" documentation = ( - "Universal Credit size criteria: one bedroom for the renter or " - "couple, one for each member of the benefit unit aged 16 or over who " - "is not the claimant or partner, one for each non-dependant aged 16 or " - "over, and the children's bedrooms. A qualifying young person the " - "renter is responsible for has their own bedroom; any other member " - "aged 16 or over is a non-dependant and has one too, except a " - "qualifying young person no one is responsible for, such as one " - "looked after by a local authority. Joint tenants and other sharers " - "of the rent, boarders and lodgers are not non-dependants, so they " - "add no bedroom to anyone's entitlement; only the household head's " - "family has non-dependants from other families (see " + "Universal Credit size criteria for the renter's extended benefit " + "unit: one bedroom for the renter or couple, one for each member of " + "the benefit unit aged 16 or over who is not the claimant or partner, " + "one for each non-dependant aged 16 or over, the children's bedrooms, " + "and the additional bedrooms for overnight care and foster parents " + "(see LHA_additional_bedrooms). A qualifying young person the renter " + "is responsible for has their own bedroom; any other member aged 16 " + "or over is a non-dependant and has one too, except a qualifying " + "young person no one is responsible for, such as one looked after by " + "a local authority. The children are the renter's own children and " + "the children of the household head's non-dependants, such as a " + "grandchild whose parent lives with the renter; they share rooms " + "with each other. A child looked after by a local authority, such as " + "a foster child, is no one's responsibility and has no bedroom. Joint " + "tenants and other sharers of the rent, boarders and lodgers are not " + "non-dependants, so neither they nor their children add a bedroom to " + "anyone's entitlement; only the household head's family has " + "non-dependants from other families (see " "is_non_dependant_of_household_head)." ) definition_period = YEAR reference = ( "https://www.legislation.gov.uk/uksi/2013/376/schedule/4/paragraph/9", "https://www.legislation.gov.uk/uksi/2013/376/schedule/4/paragraph/10", + "https://www.legislation.gov.uk/uksi/2013/376/schedule/4/paragraph/12", "https://www.legislation.gov.uk/uksi/2013/376/regulation/4", + "https://www.legislation.gov.uk/uksi/2013/376/regulation/4A", "https://www.legislation.gov.uk/uksi/2013/376/regulation/5", ) @@ -67,25 +104,50 @@ def formula(benunit, period, parameters): # A child is a person under 16 (WRA 2012 s.40). aged_16_or_over = person("age", period) >= 16 family_member = aged_16_or_over & ~person("is_claimant_or_partner", period) - # UC Regs 2013 Sch 4 para 10(1)(b): a qualifying young person for - # whom the renter is responsible (regs 4 and 5). - qualifying_young_person = family_member & person( + # UC Regs 2013 reg 4: a person is responsible for a child or + # qualifying young person who normally lives with them, but no one is + # responsible for one looked after by a local authority (reg 4(6)(a)), + # such as a foster child, unless reg 4A applies (for example a child + # placed for adoption). + responsible = person( "is_child_or_qualifying_young_person_for_universal_credit", period ) + qualifying = person("is_qualifying_young_person_for_universal_credit", period) + no_one_responsible = ( + person("is_child_for_universal_credit", period) | qualifying + ) & ~responsible + # UC Regs 2013 Sch 4 para 10(1)(b): a qualifying young person for + # whom the renter is responsible (regs 4 and 5). + qualifying_young_person = family_member & responsible # Para 10(1)(c) with para 9(2): any other member aged 16 or over is a # non-dependant, unless they are a qualifying young person for whom # no one is responsible (para 9(2)(g); reg 4(6)). - family_non_dependant = family_member & ~person( - "is_qualifying_young_person_for_universal_credit", period - ) + family_non_dependant = family_member & ~qualifying family_rooms = benunit.sum(qualifying_young_person | family_non_dependant) - # Para 10(1)(c): a non-dependant from another family who is not a - # child. - non_dependant = aged_16_or_over & person( - "is_non_dependant_of_household_head", period + # Para 9(1)(c) and 9(2): people of other families in the household + # who are non-dependants of the household head's family. Para 9(2)(g) + # excludes a child or qualifying young person no one in the extended + # benefit unit is responsible for, such as a non-dependant's foster + # child; a non-dependant's own child is their responsibility (reg + # 4(2)) and so is a non-dependant too. + non_dependant = ( + person("is_non_dependant_of_household_head", period) & ~no_one_responsible ) head_family = benunit.any(person("is_household_head", period)) - non_dependants = head_family * benunit.max(person.household.sum(non_dependant)) - return ( - 1 + family_rooms + non_dependants + bedrooms_for_children(benunit, period) + # Para 10(1)(c): a non-dependant who is not a child. + non_dependants = head_family * benunit.max( + person.household.sum(non_dependant & aged_16_or_over) + ) + # Para 10(1)(d)-(f): the children in the extended benefit unit, the + # renter's own and their non-dependants', allotted to the fewest + # bedrooms (para 10(2)). A foster child is in no one's extended + # benefit unit (paras 9(1)(b), 9(2)(c) and 9(3); reg 4(6)(a)). + children = bedrooms_for_children( + benunit, + period, + own_child=responsible, + other_child=non_dependant, ) + # Para 10(3)(b) and para 12: additional bedrooms. + additional = benunit("LHA_additional_bedrooms", period) + return 1 + family_rooms + non_dependants + children + additional diff --git a/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_additional_bedrooms.py b/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_additional_bedrooms.py new file mode 100644 index 000000000..41c9b637b --- /dev/null +++ b/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_additional_bedrooms.py @@ -0,0 +1,44 @@ +from policyengine_uk.model_api import * + + +class housing_benefit_LHA_additional_bedrooms(Variable): + value_type = float + entity = BenUnit + label = "Additional bedrooms in the Housing Benefit size criteria" + documentation = ( + "One additional bedroom if the claimant, partner, another occupier " + "or a child placed with the claimant needs overnight care (see " + "meets_lha_overnight_care_condition), and one if the claimant or " + "partner is a qualifying parent or carer (see " + "is_housing_benefit_qualifying_parent_or_carer): two if both. " + "Occupiers outside the family count for the household head's family: " + "non-dependants, boarders and lodgers and their children, but not a " + "sharer of the rent. Children and couples who cannot share a bedroom " + "because of disability are not modelled." + ) + definition_period = YEAR + reference = ( + "https://www.legislation.gov.uk/uksi/2006/213/regulation/13D", + "https://www.legislation.gov.uk/uksi/2006/214/regulation/13D", + "https://www.legislation.gov.uk/uksi/2006/213/regulation/2", + ) + + def formula(benunit, period, parameters): + person = benunit.members + overnight_care = person("meets_lha_overnight_care_condition", period) + # HB Regs 2006 reg 13D(3A)(a)(iii) and 13D(12): occupiers of other + # families, other than a joint tenant outside the claimant's + # household. + head_family = person.benunit.any(person("is_household_head", period)) + sharer = person.benunit("liable_for_share_of_household_rent", period) + other = overnight_care & ~head_family & ~sharer + is_head_family = benunit.any(person("is_household_head", period)) + others = is_head_family * benunit.max(person.household.sum(other)) + # Reg 13D(3A)(a)(i)-(iv): the claimant, partner, other members of the + # family, and a child or young person for whom the claimant or + # partner is a qualifying parent or carer. + overnight_room = benunit.any(overnight_care) | (others > 0) + # Reg 13D(3A)(b). + carer_room = benunit("is_housing_benefit_qualifying_parent_or_carer", period) + # Reg 13D(3B): two additional bedrooms where both apply. + return 1.0 * overnight_room + 1.0 * carer_room diff --git a/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_allowed_bedrooms.py b/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_allowed_bedrooms.py index 12ff521ea..36929674a 100644 --- a/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_allowed_bedrooms.py +++ b/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_allowed_bedrooms.py @@ -10,13 +10,19 @@ class housing_benefit_LHA_allowed_bedrooms(Variable): label = "Bedrooms in the Housing Benefit size criteria" documentation = ( "Housing Benefit size criteria: one bedroom for the claimant or " - "couple, one for each other occupier aged 16 or over, and the " - "children's bedrooms. Occupiers are everyone who lives in the " - "dwelling as their home except a joint tenant outside the claimant's " - "household. So every member of the benefit unit aged 16 or over who " - "is not the claimant or partner adds a bedroom, such as a young " - "person in full-time education; so do a householder's boarder or " - "lodger and a non-dependant, but a sharer of the rent does not. A " + "couple, one for each other occupier aged 16 or over, the bedrooms " + "for the occupiers' children, and the additional bedrooms for " + "overnight care and qualifying parents or carers (see " + "housing_benefit_LHA_additional_bedrooms). Occupiers are everyone " + "who lives in the dwelling as their home except a joint tenant " + "outside the claimant's household. So every member of the benefit " + "unit aged 16 or over who is not the claimant or partner adds a " + "bedroom, such as a young person in full-time education; so do a " + "householder's boarder or lodger and a non-dependant, but a sharer " + "of the rent does not. The children of a non-dependant, boarder or " + "lodger are occupiers too, and share rooms with the claimant's " + "children. A child or young person placed with the claimant or " + "partner as a foster child or for adoption is not an occupier. A " "sharer's, boarder's or lodger's own claim counts only their own " "family." ) @@ -26,26 +32,41 @@ class housing_benefit_LHA_allowed_bedrooms(Variable): "https://www.legislation.gov.uk/uksi/2006/214/regulation/13D", "https://www.legislation.gov.uk/uksi/2006/213/regulation/2", "https://www.legislation.gov.uk/uksi/2006/214/regulation/2", + "https://www.legislation.gov.uk/uksi/2006/213/regulation/21", + "https://www.legislation.gov.uk/uksi/2006/214/regulation/21", ) def formula(benunit, period, parameters): person = benunit.members # A child is a person under 16 (HB Regs 2006 reg 2(1)). aged_16_or_over = person("age", period) >= 16 + # HB Regs 2006 reg 21(3): a child or young person placed with the + # claimant or partner as a foster child or for adoption does not + # occupy the claimant's dwelling. + occupier = ~person("is_child_or_young_person_placed_with_family", period) # HB Regs 2006 reg 13D(3)(b): a person who is not a child, here a # member of the benefit unit other than the claimant or partner. family_rooms = benunit.sum( - aged_16_or_over & ~person("is_claimant_or_partner", period) + aged_16_or_over & ~person("is_claimant_or_partner", period) & occupier ) head_family = person.benunit.any(person("is_household_head", period)) sharer = person.benunit("liable_for_share_of_household_rent", period) - # Reg 13D(3)(b) for occupiers outside the family, as defined in - # 13D(12). - other_occupier = aged_16_or_over & ~head_family & ~sharer + # Reg 13D(3) for occupiers outside the family, as defined in 13D(12): + # everyone in a non-dependant's, boarder's or lodger's family, + # including their children. + other_occupier = ~head_family & ~sharer is_head_family = benunit.any(person("is_household_head", period)) other_occupiers = is_head_family * benunit.max( - person.household.sum(other_occupier) + person.household.sum(other_occupier & aged_16_or_over) ) - return ( - 1 + family_rooms + other_occupiers + bedrooms_for_children(benunit, period) + # Reg 13D(3)(c)-(e): the occupiers' children, the claimant's own and + # other families', share rooms with each other. + children = bedrooms_for_children( + benunit, + period, + own_child=occupier, + other_child=other_occupier, ) + # Reg 13D(3A) and (3B): additional bedrooms. + additional = benunit("housing_benefit_LHA_additional_bedrooms", period) + return 1 + family_rooms + other_occupiers + children + additional diff --git a/policyengine_uk/variables/gov/dwp/is_child_or_young_person_for_legacy_benefits.py b/policyengine_uk/variables/gov/dwp/is_child_or_young_person_for_legacy_benefits.py index 7091a5791..b456a6ba9 100644 --- a/policyengine_uk/variables/gov/dwp/is_child_or_young_person_for_legacy_benefits.py +++ b/policyengine_uk/variables/gov/dwp/is_child_or_young_person_for_legacy_benefits.py @@ -11,8 +11,10 @@ class is_child_or_young_person_for_legacy_benefits(Variable): (SSCBA 1992 s.142), excluding young persons entitled to a benefit in their own right. That is the Child Benefit child or qualifying young person test, restricted to members who are not the claimant or partner. - A child or young person placed with the claimant by a local authority is - not a member of the claimant's household (IS reg 16(4); HB reg 21(3)). + A child or young person placed with the claimant by a local authority, + such as a foster child, or placed for adoption is not a member of the + claimant's household (IS reg 16(4); JSA reg 78(4); ESA reg 156(5); HB reg + 21(3)). """ value_type = bool @@ -28,11 +30,13 @@ class is_child_or_young_person_for_legacy_benefits(Variable): "https://www.legislation.gov.uk/uksi/2012/2885/regulation/2", "https://www.legislation.gov.uk/uksi/1987/1967/regulation/16", "https://www.legislation.gov.uk/uksi/2006/213/regulation/21", + "https://www.legislation.gov.uk/uksi/1996/207/regulation/78", + "https://www.legislation.gov.uk/uksi/2008/794/regulation/156", ) def formula(person, period, parameters): return ( person("is_child_or_qualifying_young_person_for_child_benefit", period) & ~person("is_claimant_or_partner", period) - & ~person("is_looked_after_by_local_authority", period) + & ~person("is_child_or_young_person_placed_with_family", period) ) diff --git a/policyengine_uk/variables/gov/dwp/is_child_or_young_person_placed_with_family.py b/policyengine_uk/variables/gov/dwp/is_child_or_young_person_placed_with_family.py new file mode 100644 index 000000000..592130460 --- /dev/null +++ b/policyengine_uk/variables/gov/dwp/is_child_or_young_person_placed_with_family.py @@ -0,0 +1,42 @@ +from policyengine_uk.model_api import * + + +class is_child_or_young_person_placed_with_family(Variable): + value_type = bool + entity = Person + label = "Child or young person placed with the family by a local authority or for adoption" + documentation = ( + "A child or young person (the Child Benefit definition) who is not " + "the claimant or partner and is placed with their benefit unit by a " + "local authority, such as a foster child (see " + "is_looked_after_by_local_authority), or placed for adoption (see " + "is_placed_for_adoption). Under Income Support, income-based " + "Jobseeker's Allowance, income-related Employment and Support " + "Allowance and Housing Benefit they are not a member of the " + "claimant's household, and under Housing Benefit they do not occupy " + "the claimant's dwelling. HB reg 21(3)(a) refers to a placement " + "under section 22C(2) of the Children Act 1989; the model follows " + "DWP's guidance that foster children are within reg 21(3) (LHA " + "Guidance Manual para 2.033)." + ) + definition_period = YEAR + reference = ( + "https://www.legislation.gov.uk/uksi/2006/213/regulation/21", + "https://www.legislation.gov.uk/uksi/2006/214/regulation/21", + "https://www.legislation.gov.uk/uksi/1987/1967/regulation/16", + "https://www.legislation.gov.uk/uksi/1996/207/regulation/78", + "https://www.legislation.gov.uk/uksi/2008/794/regulation/156", + "https://assets.publishing.service.gov.uk/media/5a758238ed915d6faf2b38a2/lha-guidance-manual.pdf", + ) + + def formula(person, period, parameters): + # HB Regs 2006 reg 21(3)(a)-(c); IS Regs 1987 reg 16(4); JSA Regs + # 1996 reg 78(4); ESA Regs 2008 reg 156(5). + placed = person("is_looked_after_by_local_authority", period) | person( + "is_placed_for_adoption", period + ) + return ( + placed + & person("is_child_or_qualifying_young_person_for_child_benefit", period) + & ~person("is_claimant_or_partner", period) + ) diff --git a/policyengine_uk/variables/gov/dwp/is_housing_benefit_qualifying_parent_or_carer.py b/policyengine_uk/variables/gov/dwp/is_housing_benefit_qualifying_parent_or_carer.py new file mode 100644 index 000000000..d95878735 --- /dev/null +++ b/policyengine_uk/variables/gov/dwp/is_housing_benefit_qualifying_parent_or_carer.py @@ -0,0 +1,37 @@ +from policyengine_uk.model_api import * + + +class is_housing_benefit_qualifying_parent_or_carer(Variable): + value_type = bool + entity = BenUnit + label = "Housing Benefit claimant or partner is a qualifying parent or carer" + documentation = ( + "Whether the claimant or partner has a child or young person placed " + "with them as a foster child or for adoption (see " + "is_child_or_young_person_placed_with_family), or is an approved " + "foster parent who has had no child placed with them for at most 52 " + "weeks (is_approved_foster_parent_without_placement). The claimant " + "gets one additional bedroom, and is not a young individual for the " + "shared accommodation rate. The definition also requires a bedroom " + "in the dwelling additional to those the occupiers use; the model " + "does not observe the dwelling's bedrooms and assumes there is one." + ) + definition_period = YEAR + reference = ( + "https://www.legislation.gov.uk/uksi/2006/213/regulation/2", + "https://www.legislation.gov.uk/uksi/2006/214/regulation/2", + "https://www.legislation.gov.uk/uksi/2006/213/regulation/13D", + "https://www.legislation.gov.uk/uksi/2006/213/regulation/21", + ) + + def formula(benunit, period, parameters): + person = benunit.members + # HB Regs 2006 reg 2(1), "qualifying parent or carer", (a): a child + # or young person placed with them as mentioned in reg 21(3). + placed = person("is_child_or_young_person_placed_with_family", period) + # (b): an approved foster parent with no placement for at most 52 + # weeks. + between_placements = person("is_claimant_or_partner", period) & person( + "is_approved_foster_parent_without_placement", period + ) + return benunit.any(placed | between_placements) diff --git a/policyengine_uk/variables/gov/dwp/is_housing_benefit_young_individual.py b/policyengine_uk/variables/gov/dwp/is_housing_benefit_young_individual.py index f66e7af8e..d54721850 100644 --- a/policyengine_uk/variables/gov/dwp/is_housing_benefit_young_individual.py +++ b/policyengine_uk/variables/gov/dwp/is_housing_benefit_young_individual.py @@ -7,17 +7,29 @@ class is_housing_benefit_young_individual(Variable): label = "Young individual (Housing Benefit)" documentation = ( "A single claimant (no partner and not a lone parent) under the " - "shared accommodation age threshold. The exceptions for a housing " - "association landlord, care leavers, former hostel residents, " - "offenders under multi-agency management, people who need overnight " - "care, qualifying parents or carers, victims of domestic violence " - "and of modern slavery are not identified." + "shared accommodation age threshold, other than one who requires " + "overnight care (see meets_lha_overnight_care_condition) or is a " + "qualifying parent or carer (see " + "is_housing_benefit_qualifying_parent_or_carer). The exceptions for " + "a housing association landlord, care leavers, former hostel " + "residents, offenders under multi-agency management, and victims of " + "domestic violence and of modern slavery are not identified." ) definition_period = YEAR reference = "https://www.legislation.gov.uk/uksi/2006/213/regulation/2" def formula(benunit, period, parameters): threshold = parameters(period).gov.dwp.LHA.shared_accommodation_age_threshold - return benunit("is_single_person", period) & ( - benunit("eldest_claimant_or_partner_age", period) < threshold + person = benunit.members + # HB Regs 2006 reg 2(1), "young individual": not a claimant who is a + # person who requires overnight care or a qualifying parent or carer. + requires_overnight_care = benunit.any( + person("is_claimant_or_partner", period) + & person("meets_lha_overnight_care_condition", period) + ) + return ( + benunit("is_single_person", period) + & (benunit("eldest_claimant_or_partner_age", period) < threshold) + & ~requires_overnight_care + & ~benunit("is_housing_benefit_qualifying_parent_or_carer", period) ) diff --git a/policyengine_uk/variables/gov/dwp/is_lha_shared_accommodation_rate_specified_renter.py b/policyengine_uk/variables/gov/dwp/is_lha_shared_accommodation_rate_specified_renter.py index 2e43025fa..b288b574d 100644 --- a/policyengine_uk/variables/gov/dwp/is_lha_shared_accommodation_rate_specified_renter.py +++ b/policyengine_uk/variables/gov/dwp/is_lha_shared_accommodation_rate_specified_renter.py @@ -10,10 +10,11 @@ class is_lha_shared_accommodation_rate_specified_renter(Variable): "accommodation age threshold, not responsible for a child or young " "person under the UC or Housing Benefit rules, no non-dependant under " "the household composition proxy, and not excepted by a disability " - "benefit (UC Schedule 4 paragraph 29(5)). Other paragraph 29 " - "exceptions and couples claiming as single people are not modelled. " - "The same category serves Housing Benefit, whose young-individual " - "definition (HB regulation 2(1)) has no disability exception." + "benefit (UC Schedule 4 paragraph 29(5)) or as a foster parent or " + "adopter (paragraph 29(9A)). Other paragraph 29 exceptions and " + "couples claiming as single people are not modelled. Housing Benefit " + "has its own young-individual test: see " + "is_housing_benefit_young_individual." ) definition_period = YEAR reference = ( @@ -29,14 +30,19 @@ def formula(benunit, period, parameters): p = parameters(period).gov.dwp.LHA person = benunit.members # UC Sch 4 para 29(5): a renter under 35 receiving - # attendance allowance, DLA care at the middle or highest rate, or the - # PIP daily living component is excepted. Other para 29 exceptions - # (care leavers, hostel residents, MAPPA, domestic abuse, modern - # slavery, foster parents) are not observed. + # attendance allowance (which includes armed forces independence + # payment, reg 2), DLA care at the middle or highest rate, or the PIP + # daily living component is excepted. Other para 29 exceptions (care + # leavers, hostel residents, MAPPA, domestic abuse, modern slavery) + # are not observed. excepted_disabled_renter = benunit.any( person("is_claimant_or_partner", period) & (add(person, period, p.shared_accommodation_exception_benefits) > 0) ) + # Para 29(9A): a renter who satisfies the foster parent condition. + excepted_foster_parent = benunit( + "lha_renter_meets_foster_parent_condition", period + ) return ( ~benunit("is_couple", period) & ( @@ -49,4 +55,5 @@ def formula(benunit, period, parameters): ) & ~benunit("lha_renter_has_non_dependant", period) & ~excepted_disabled_renter + & ~excepted_foster_parent ) diff --git a/policyengine_uk/variables/gov/dwp/is_non_dependant_of_household_head.py b/policyengine_uk/variables/gov/dwp/is_non_dependant_of_household_head.py index 2c80db627..5042743e1 100644 --- a/policyengine_uk/variables/gov/dwp/is_non_dependant_of_household_head.py +++ b/policyengine_uk/variables/gov/dwp/is_non_dependant_of_household_head.py @@ -15,8 +15,10 @@ class is_non_dependant_of_household_head(Variable): "Credit counts a non-dependant in one claim only, which the model " "gives to the household head's family; Housing Benefit and Council " "Tax Reduction apportion a non-dependant of several joint occupiers " - "between them. Foster children and carers engaged through a charity " - "are not identified." + "between them. A non-dependant's own children are non-dependants " + "too; a child looked after by a local authority is not (see " + "LHA_allowed_bedrooms). Carers engaged through a charity are not " + "identified." ) definition_period = YEAR reference = ( diff --git a/policyengine_uk/variables/gov/dwp/lha_renter_has_non_dependant.py b/policyengine_uk/variables/gov/dwp/lha_renter_has_non_dependant.py index 31f652b56..5d0f6f3ce 100644 --- a/policyengine_uk/variables/gov/dwp/lha_renter_has_non_dependant.py +++ b/policyengine_uk/variables/gov/dwp/lha_renter_has_non_dependant.py @@ -12,12 +12,14 @@ class lha_renter_has_non_dependant(Variable): "household head (see is_non_dependant_of_household_head): joint " "tenants and other sharers of the rent, boarders and lodgers are not " "non-dependants, and a sharer, boarder or lodger has none from the " - "household head's family. Foster children are not identified." + "household head's family. A child or young person placed with the " + "family as a foster child or for adoption is not a non-dependant." ) definition_period = YEAR reference = ( "https://www.legislation.gov.uk/uksi/2013/376/schedule/4/paragraph/9", "https://www.legislation.gov.uk/uksi/2006/213/regulation/3", + "https://www.legislation.gov.uk/uksi/2006/213/regulation/21", ) def formula(benunit, period, parameters): @@ -26,9 +28,13 @@ def formula(benunit, period, parameters): # A child or young person under either scheme (UC reg 5; HB reg 19) # is a dependant, not a non-dependant. age = person("age", period) + # A foster child or a child placed for adoption is not a + # non-dependant either (UC Sch 4 para 9(2)(c) and (g); HB reg 3(2)(c) + # and reg 21(3)). child_or_qyp = ( person("is_child_or_qualifying_young_person_for_universal_credit", period) | person("is_child_or_young_person_for_legacy_benefits", period) + | person("is_child_or_young_person_placed_with_family", period) | ((age >= 16) & (age < 17)) ) within_benefit_unit = benunit.any(~claimant_or_partner & ~child_or_qyp) diff --git a/policyengine_uk/variables/gov/dwp/lha_renter_meets_foster_parent_condition.py b/policyengine_uk/variables/gov/dwp/lha_renter_meets_foster_parent_condition.py new file mode 100644 index 000000000..f4f26f299 --- /dev/null +++ b/policyengine_uk/variables/gov/dwp/lha_renter_meets_foster_parent_condition.py @@ -0,0 +1,40 @@ +from policyengine_uk.model_api import * + + +class lha_renter_meets_foster_parent_condition(Variable): + value_type = bool + entity = BenUnit + label = "Universal Credit renter meets the foster parent condition" + documentation = ( + "Whether the renter or a joint renter is a foster parent or an " + "adopter with whom a child has been placed for adoption. A foster " + "parent has a child under 18 looked after by a local authority " + "placed with them (a member of the benefit unit flagged " + "is_looked_after_by_local_authority), or is an approved foster " + "parent whose last placement ended, or who was approved, within 12 " + "months (is_approved_foster_parent_without_placement). The renter " + "gets one additional bedroom however many children are placed, and " + "is excepted from the shared accommodation rate." + ) + definition_period = YEAR + reference = ( + "https://www.legislation.gov.uk/uksi/2013/376/schedule/4/paragraph/12", + "https://www.legislation.gov.uk/uksi/2013/376/schedule/4/paragraph/29", + "https://www.legislation.gov.uk/uksi/2013/376/regulation/2", + ) + + def formula(benunit, period, parameters): + person = benunit.members + claimant_or_partner = person("is_claimant_or_partner", period) + # UC Regs 2013 reg 2, "foster parent": a person with whom a child is + # placed under the care planning regulations; a child here is a + # person under 18 looked after by a local authority. + placed = ( + person("is_looked_after_by_local_authority", period) + | person("is_placed_for_adoption", period) + ) & (person("age", period) < 18) + # UC Regs 2013 Sch 4 para 12(4)(a)-(b) and (5). + between_placements = claimant_or_partner & person( + "is_approved_foster_parent_without_placement", period + ) + return benunit.any((placed & ~claimant_or_partner) | between_placements) diff --git a/policyengine_uk/variables/gov/dwp/meets_lha_overnight_care_condition.py b/policyengine_uk/variables/gov/dwp/meets_lha_overnight_care_condition.py new file mode 100644 index 000000000..ad86b14b6 --- /dev/null +++ b/policyengine_uk/variables/gov/dwp/meets_lha_overnight_care_condition.py @@ -0,0 +1,34 @@ +from policyengine_uk.model_api import * + + +class meets_lha_overnight_care_condition(Variable): + value_type = bool + entity = Person + label = "Meets the LHA overnight care condition" + documentation = ( + "Whether this person receives a qualifying disability benefit " + "(attendance allowance or armed forces independence payment, the " + "care component of Disability Living Allowance at the middle or " + "highest rate, or the daily living component of Personal " + "Independence Payment) and has non-resident carers who regularly " + "stay overnight to care for them. This is the Universal Credit " + "overnight care condition and the Housing Benefit 'person who " + "requires overnight care'. Two Housing Benefit routes are not " + "modelled: a person without a qualifying benefit whose need the " + "local authority accepts on other evidence, and the requirement that " + "the carers have the use of a bedroom additional to the occupiers'." + ) + definition_period = YEAR + reference = ( + "https://www.legislation.gov.uk/uksi/2013/376/schedule/4/paragraph/12", + "https://www.legislation.gov.uk/uksi/2006/213/regulation/2", + "https://www.legislation.gov.uk/uksi/2006/214/regulation/2", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.dwp.LHA + # UC Regs 2013 Sch 4 para 12(3)(a); HB Regs 2006 reg 2(1), "person + # who requires overnight care", (a)(i)-(iib). + qualifying_benefit = add(person, period, p.overnight_care_benefits) > 0 + # UC para 12(3)(b)-(c); HB reg 2(1), (b). + return qualifying_benefit & person("has_non_resident_overnight_carer", period) diff --git a/policyengine_uk/variables/household/demographic/has_non_resident_overnight_carer.py b/policyengine_uk/variables/household/demographic/has_non_resident_overnight_carer.py new file mode 100644 index 000000000..e60811980 --- /dev/null +++ b/policyengine_uk/variables/household/demographic/has_non_resident_overnight_carer.py @@ -0,0 +1,21 @@ +from policyengine_uk.model_api import * + + +class has_non_resident_overnight_carer(Variable): + value_type = bool + entity = Person + label = "has a non-resident overnight carer" + documentation = ( + "Whether one or more people who do not live in the home are engaged, " + "under arrangements made for that purpose, to provide this person " + "with overnight care and to stay overnight in the home on a regular " + "basis. With a qualifying disability benefit, this gives the " + "household an additional bedroom in the Universal Credit and Housing " + "Benefit size criteria (see meets_lha_overnight_care_condition)." + ) + definition_period = YEAR + default_value = False + reference = ( + "https://www.legislation.gov.uk/uksi/2013/376/schedule/4/paragraph/12", + "https://www.legislation.gov.uk/uksi/2006/213/regulation/2", + ) diff --git a/policyengine_uk/variables/household/demographic/is_approved_foster_parent_without_placement.py b/policyengine_uk/variables/household/demographic/is_approved_foster_parent_without_placement.py new file mode 100644 index 000000000..402cfae68 --- /dev/null +++ b/policyengine_uk/variables/household/demographic/is_approved_foster_parent_without_placement.py @@ -0,0 +1,22 @@ +from policyengine_uk.model_api import * + + +class is_approved_foster_parent_without_placement(Variable): + value_type = bool + entity = Person + label = "approved foster parent between placements" + documentation = ( + "Whether this person is an approved foster parent (in Scotland, a " + "foster carer or kinship carer) with no child currently placed with " + "them, whose last placement ended, or who was approved and has had " + "no placement since, no more than 12 months ago. Housing Benefit's " + "limit is 52 weeks. Such a person keeps the foster parent's " + "additional bedroom (UC Regs 2013 Sch 4 para 12(5); HB Regs 2006 " + "reg 2(1), 'qualifying parent or carer')." + ) + definition_period = YEAR + default_value = False + reference = ( + "https://www.legislation.gov.uk/uksi/2013/376/schedule/4/paragraph/12", + "https://www.legislation.gov.uk/uksi/2006/213/regulation/2", + ) diff --git a/policyengine_uk/variables/household/demographic/is_looked_after_by_local_authority.py b/policyengine_uk/variables/household/demographic/is_looked_after_by_local_authority.py index d2a18247a..96b158ba7 100644 --- a/policyengine_uk/variables/household/demographic/is_looked_after_by_local_authority.py +++ b/policyengine_uk/variables/household/demographic/is_looked_after_by_local_authority.py @@ -5,6 +5,24 @@ class is_looked_after_by_local_authority(Variable): value_type = bool entity = Person label = "looked after by a local authority" + documentation = ( + "Whether this child or young person is looked after by a local " + "authority. A looked-after child who lives in the household, such as " + "a foster child, is placed with the family whose benefit unit they " + "are in: no one in it is responsible for them under Universal Credit " + "(UC Regs 2013 reg 4(6)(a)), they are not a member of the claimant's " + "household under Housing Benefit and the other legacy schemes (HB " + "Regs 2006 reg 21(3)), they have no bedroom of their own in the size " + "criteria, and their carer meets the foster parent condition for an " + "additional bedroom. Leave it false for a child placed for adoption " + "(see is_placed_for_adoption) or placed with their own parent, for " + "whom Universal Credit treats the carer as responsible (reg 4A)." + ) definition_period = YEAR default_value = False - reference = "https://www.legislation.gov.uk/uksi/2015/448/regulation/4" + reference = ( + "https://www.legislation.gov.uk/uksi/2015/448/regulation/4", + "https://www.legislation.gov.uk/uksi/2013/376/regulation/4", + "https://www.legislation.gov.uk/uksi/2013/376/regulation/4A", + "https://www.legislation.gov.uk/uksi/2006/213/regulation/21", + ) diff --git a/policyengine_uk/variables/household/demographic/is_placed_for_adoption.py b/policyengine_uk/variables/household/demographic/is_placed_for_adoption.py new file mode 100644 index 000000000..533c79119 --- /dev/null +++ b/policyengine_uk/variables/household/demographic/is_placed_for_adoption.py @@ -0,0 +1,25 @@ +from policyengine_uk.model_api import * + + +class is_placed_for_adoption(Variable): + value_type = bool + entity = Person + label = "placed for adoption" + documentation = ( + "Whether this child is placed for adoption with the claimant or " + "partner of their benefit unit (an adopter), or placed with them " + "prior to adoption. Put the child in the adopter's benefit unit and " + "leave is_looked_after_by_local_authority false: under Universal " + "Credit the adopter is responsible for the child (UC Regs 2013 reg " + "4A(1)(c)) and satisfies the foster parent condition for an " + "additional bedroom (Sch 4 para 12(4)(b)); under Housing Benefit and " + "the other legacy schemes the child is not a member of the " + "claimant's household (HB Regs 2006 reg 21(3)(b)-(c))." + ) + definition_period = YEAR + default_value = False + reference = ( + "https://www.legislation.gov.uk/uksi/2013/376/regulation/4A", + "https://www.legislation.gov.uk/uksi/2013/376/schedule/4/paragraph/12", + "https://www.legislation.gov.uk/uksi/2006/213/regulation/21", + ) From 8e42058d202e9d090d6981674e86f1022eac4c0b Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Thu, 1 Oct 2026 14:42:35 -0400 Subject: [PATCH 2/8] Treat a child placed with any family as no Housing Benefit occupier HB reg 21(3) names only children placed with the claimant or partner, but DWP treats foster children as not occupying the dwelling (LHA Guidance Manual para 2.033; HB circular A21/2013 para 22), as Universal Credit does (UC Sch 4 para 9(2)(g)). The household head's Housing Benefit size criteria and overnight-care bedroom now leave out a child placed with a non-dependant, boarder or lodger as a foster child or for adoption. Adds a YAML case and tightens the foster-child Hypothesis property to an exact effect on every family. Co-Authored-By: Claude Opus 5.5 --- ...lies_children_and_additional_bedrooms.yaml | 38 ++++++++++++++++ ...est_lha_bedroom_young_people_properties.py | 44 ++++++++----------- ...housing_benefit_LHA_additional_bedrooms.py | 13 ++++-- .../housing_benefit_LHA_allowed_bedrooms.py | 12 +++-- 4 files changed, 74 insertions(+), 33 deletions(-) diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_other_families_children_and_additional_bedrooms.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_other_families_children_and_additional_bedrooms.yaml index 0164ea54e..c499c5bae 100644 --- a/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_other_families_children_and_additional_bedrooms.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_other_families_children_and_additional_bedrooms.yaml @@ -207,6 +207,44 @@ LHA_allowed_bedrooms: [1, 2] housing_benefit_LHA_allowed_bedrooms: [1, 2] +- name: A non-dependant's foster child does not count for the renter + period: 2026 + input: + people: + renter: + age: 60 + is_household_head: true + daughter: + age: 32 + is_male: false + foster_child: + age: 6 + is_looked_after_by_local_authority: true + benunits: + renter_family: + members: [renter] + daughter_family: + members: [daughter, foster_child] + households: + home: + members: [renter, daughter, foster_child] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + # UC: no one in the renter's extended benefit unit is responsible for a + # looked-after child (reg 4(6)(a)), so the child is not a non-dependant + # (para 9(2)(g)): the renter and the daughter, 2 bedrooms. + LHA_allowed_bedrooms: [2, 2] + # HB: reg 21(3) names only a child placed with the claimant or partner, + # but DWP treats foster children as not occupying the dwelling (LHA + # Guidance Manual para 2.033; circular A21/2013 para 22), and the model + # follows it: 2 bedrooms. The daughter's own size criteria include the + # foster parent's or qualifying parent or carer's additional bedroom. + housing_benefit_LHA_allowed_bedrooms: [2, 2] + LHA_additional_bedrooms: [0, 1] + housing_benefit_LHA_additional_bedrooms: [0, 1] + - name: Foster children have no bedrooms of their own; the foster parent has one additional bedroom period: 2026 input: diff --git a/policyengine_uk/tests/test_lha_bedroom_young_people_properties.py b/policyengine_uk/tests/test_lha_bedroom_young_people_properties.py index efbec9389..db44dad3e 100644 --- a/policyengine_uk/tests/test_lha_bedroom_young_people_properties.py +++ b/policyengine_uk/tests/test_lha_bedroom_young_people_properties.py @@ -20,16 +20,18 @@ household head's family also gains one bedroom under both schemes if the person joins a non-dependant's family (UC: unless no one is responsible for them), and one Housing Benefit bedroom if they join a boarder's or - lodger's family. No other family's bedrooms change. + lodger's family (HB: unless placed with it as a foster child). No other + family's bedrooms change. 3. Children: adding a child under 16 who is neither fostered nor placed for adoption to any family never lowers any family's bedrooms under either scheme and raises each by at most one. 4. Foster children: adding a foster child to a family gives that family one more bedroom under each scheme if it did not already meet the foster parent condition (UC) or have a qualifying parent or carer (HB), and none - otherwise. No other family's Universal Credit bedrooms change; the - household head's Housing Benefit bedrooms rise by at most one when the - child is placed with an occupier's family, whose children are occupiers. + otherwise. No other family's bedrooms change under either scheme: a + child placed with another family is not in the household head's + extended benefit unit (UC para 9(2)(g)) and, following DWP, not an + occupier (HB; LHA Guidance Manual para 2.033). 5. Reference: every family's bedrooms, and its additional bedrooms, equal an independent count of the size criteria: - one for the claimant or couple; @@ -38,15 +40,15 @@ family as a foster child); - for the household head's family, one for each person aged 16 or over in a non-dependant's family (and, for HB, in a boarder's or lodger's - family); + family), except one no one is responsible for (UC) or placed with that + family as a foster child (HB); - the fewest rooms that hold the counted children under 16 two to a room, where only children of the same sex or two children under 10 may share, found by brute force. UC counts the family's own children and, for the household head's family, the non-dependants' children, but no - foster child. HB counts the family's own children other than foster - children and children placed for adoption and, for the household - head's family, every child of a non-dependant's, boarder's or lodger's - family; + foster child. HB counts the children of the family and, for the + household head's family, of a non-dependant's, boarder's or lodger's + family, other than foster children and children placed for adoption; - one additional bedroom if anyone so counted, or a foster child of the family, has overnight care, and one if the family fosters, has a child placed for adoption, or has an approved foster parent between @@ -298,9 +300,8 @@ def test_exact_effect_of_adding_a_person_aged_16_to_19(case): head = keys.index((target[0], 0)) if fam["role"] == "non_dependant": expected_uc[head] += 0 if added["unclaimed"] else 1 - expected_hb[head] += 1 - elif fam["role"] in ("boarder", "lodger"): - expected_hb[head] += 1 + if fam["role"] in ("non_dependant", "boarder", "lodger"): + expected_hb[head] += 0 if added["placed"] else 1 assert np.array_equal(uc_after - uc_before, expected_uc) assert np.array_equal(hb_after - hb_before, expected_hb) @@ -333,16 +334,7 @@ def test_a_foster_child_adds_only_the_foster_parents_bedroom(case): expected_uc = np.zeros(len(keys)) expected_uc[t] = new_carer assert np.array_equal(uc_after - uc_before, expected_uc) - hb_change = hb_after - hb_before - assert hb_change[t] == new_carer - head = keys.index((target[0], 0)) - for b in range(len(keys)): - if b == t: - continue - if b == head and fam["role"] in ("non_dependant", "boarder", "lodger"): - assert hb_change[b] in (0, 1) - else: - assert hb_change[b] == 0 + assert np.array_equal(hb_after - hb_before, expected_uc) @PROPERTY_SETTINGS @@ -388,10 +380,12 @@ def test_bedrooms_match_an_independent_count_of_the_size_criteria(case): c[3] for c in other["children"] if c[2] != "foster" ) if other["role"] in ("non_dependant", "boarder", "lodger"): - hb_rooms += len(other["adults"]) + int(joins) - hb_children += list(other["children"]) + hb_rooms += len(other["adults"]) + int( + joins and not added["placed"] + ) + hb_children += [c for c in other["children"] if c[2] == "own"] hb_overnight |= any(o for _, o in other["adults"]) or any( - c[3] for c in other["children"] + c[3] for c in other["children"] if c[2] == "own" ) expected_uc_additional = int(uc_overnight) + int(uc_foster) expected_hb_additional = int(hb_overnight) + int(hb_carer) diff --git a/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_additional_bedrooms.py b/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_additional_bedrooms.py index 41c9b637b..5c9d55d1e 100644 --- a/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_additional_bedrooms.py +++ b/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_additional_bedrooms.py @@ -13,8 +13,11 @@ class housing_benefit_LHA_additional_bedrooms(Variable): "is_housing_benefit_qualifying_parent_or_carer): two if both. " "Occupiers outside the family count for the household head's family: " "non-dependants, boarders and lodgers and their children, but not a " - "sharer of the rent. Children and couples who cannot share a bedroom " - "because of disability are not modelled." + "sharer of the rent or a child placed with them as a foster child or " + "for adoption. The definitions require a bedroom in the dwelling for " + "the carer or the foster child; the model does not observe the " + "dwelling's bedrooms and assumes there is one. Children and couples " + "who cannot share a bedroom because of disability are not modelled." ) definition_period = YEAR reference = ( @@ -28,10 +31,12 @@ def formula(benunit, period, parameters): overnight_care = person("meets_lha_overnight_care_condition", period) # HB Regs 2006 reg 13D(3A)(a)(iii) and 13D(12): occupiers of other # families, other than a joint tenant outside the claimant's - # household. + # household and a child placed with another family as a foster child + # or for adoption (see housing_benefit_LHA_allowed_bedrooms). head_family = person.benunit.any(person("is_household_head", period)) sharer = person.benunit("liable_for_share_of_household_rent", period) - other = overnight_care & ~head_family & ~sharer + placed = person("is_child_or_young_person_placed_with_family", period) + other = overnight_care & ~head_family & ~sharer & ~placed is_head_family = benunit.any(person("is_household_head", period)) others = is_head_family * benunit.max(person.household.sum(other)) # Reg 13D(3A)(a)(i)-(iv): the claimant, partner, other members of the diff --git a/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_allowed_bedrooms.py b/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_allowed_bedrooms.py index 36929674a..414d2d577 100644 --- a/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_allowed_bedrooms.py +++ b/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_allowed_bedrooms.py @@ -21,8 +21,8 @@ class housing_benefit_LHA_allowed_bedrooms(Variable): "householder's boarder or lodger and a non-dependant, but a sharer " "of the rent does not. The children of a non-dependant, boarder or " "lodger are occupiers too, and share rooms with the claimant's " - "children. A child or young person placed with the claimant or " - "partner as a foster child or for adoption is not an occupier. A " + "children. A child or young person placed with a family in the " + "household as a foster child or for adoption is not an occupier. A " "sharer's, boarder's or lodger's own claim counts only their own " "family." ) @@ -42,7 +42,11 @@ def formula(benunit, period, parameters): aged_16_or_over = person("age", period) >= 16 # HB Regs 2006 reg 21(3): a child or young person placed with the # claimant or partner as a foster child or for adoption does not - # occupy the claimant's dwelling. + # occupy the claimant's dwelling. Reg 21(3) names only placements + # with the claimant or partner; the model follows DWP in treating a + # child placed with anyone in the household as no occupier (LHA + # Guidance Manual para 2.033; HB circular A21/2013 para 22), as + # Universal Credit does (UC Sch 4 para 9(2)(g)). occupier = ~person("is_child_or_young_person_placed_with_family", period) # HB Regs 2006 reg 13D(3)(b): a person who is not a child, here a # member of the benefit unit other than the claimant or partner. @@ -54,7 +58,7 @@ def formula(benunit, period, parameters): # Reg 13D(3) for occupiers outside the family, as defined in 13D(12): # everyone in a non-dependant's, boarder's or lodger's family, # including their children. - other_occupier = ~head_family & ~sharer + other_occupier = ~head_family & ~sharer & occupier is_head_family = benunit.any(person("is_household_head", period)) other_occupiers = is_head_family * benunit.max( person.household.sum(other_occupier & aged_16_or_over) From 8e8b0876bcd93b6f31ec6434a2da1c451daeac8a Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Thu, 1 Oct 2026 16:01:02 -0400 Subject: [PATCH 3/8] Give an occupier couple one Housing Benefit bedroom HB Regs 2006 reg 13D(3)(a) puts any occupier couple in "a couple" (one bedroom; LHA Guidance Manual para 2.012), so a non-dependant's, boarder's or lodger's couple adds one bedroom to the household head's HB size criteria, not two. Universal Credit is unchanged: each non-dependant who is not a child has a bedroom (UC Sch 4 para 10(1)(c); ADM F3112 note 1). Reported by the disabled-rooms session (chip task_cc724597). Co-Authored-By: Claude Opus 5.5 --- ...lies_children_and_additional_bedrooms.yaml | 30 +++++++++++++++++++ ...est_lha_bedroom_young_people_properties.py | 6 ++-- .../housing_benefit_LHA_allowed_bedrooms.py | 14 +++++++-- 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_other_families_children_and_additional_bedrooms.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_other_families_children_and_additional_bedrooms.yaml index c499c5bae..fb3d46a03 100644 --- a/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_other_families_children_and_additional_bedrooms.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_other_families_children_and_additional_bedrooms.yaml @@ -142,6 +142,36 @@ housing_benefit_LHA_allowed_bedrooms: [3, 2] housing_benefit_LHA_category: [D, C] +- name: A non-dependant couple has a bedroom each under Universal Credit but one between them under Housing Benefit + period: 2026 + input: + people: + renter: + age: 60 + is_household_head: true + son: + age: 30 + sons_partner: + age: 29 + benunits: + renter_family: + members: [renter] + son_family: + members: [son, sons_partner] + households: + home: + members: [renter, son, sons_partner] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + # UC: each is "a non-dependant who is not a child" (para 10(1)(c); ADM + # F3112 note 1): 3 bedrooms. + LHA_allowed_bedrooms: [3, 1] + # HB: the occupier couple is one category, "a couple" (reg 13D(3)(a); + # LHA Guidance Manual para 2.012): 2 bedrooms. + housing_benefit_LHA_allowed_bedrooms: [2, 1] + - name: A lodger's child counts for Housing Benefit but not Universal Credit period: 2026 input: diff --git a/policyengine_uk/tests/test_lha_bedroom_young_people_properties.py b/policyengine_uk/tests/test_lha_bedroom_young_people_properties.py index db44dad3e..3bd022adc 100644 --- a/policyengine_uk/tests/test_lha_bedroom_young_people_properties.py +++ b/policyengine_uk/tests/test_lha_bedroom_young_people_properties.py @@ -380,9 +380,9 @@ def test_bedrooms_match_an_independent_count_of_the_size_criteria(case): c[3] for c in other["children"] if c[2] != "foster" ) if other["role"] in ("non_dependant", "boarder", "lodger"): - hb_rooms += len(other["adults"]) + int( - joins and not added["placed"] - ) + # HB reg 13D(3)(a): the family's claimant or couple + # has one bedroom. + hb_rooms += 1 + int(joins and not added["placed"]) hb_children += [c for c in other["children"] if c[2] == "own"] hb_overnight |= any(o for _, o in other["adults"]) or any( c[3] for c in other["children"] if c[2] == "own" diff --git a/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_allowed_bedrooms.py b/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_allowed_bedrooms.py index 414d2d577..2891316d1 100644 --- a/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_allowed_bedrooms.py +++ b/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_allowed_bedrooms.py @@ -19,7 +19,8 @@ class housing_benefit_LHA_allowed_bedrooms(Variable): "unit aged 16 or over who is not the claimant or partner adds a " "bedroom, such as a young person in full-time education; so do a " "householder's boarder or lodger and a non-dependant, but a sharer " - "of the rent does not. The children of a non-dependant, boarder or " + "of the rent does not. A couple, such as a non-dependant and their " + "partner, has one bedroom between them. The children of a non-dependant, boarder or " "lodger are occupiers too, and share rooms with the claimant's " "children. A child or young person placed with a family in the " "household as a foster child or for adoption is not an occupier. A " @@ -59,9 +60,18 @@ def formula(benunit, period, parameters): # everyone in a non-dependant's, boarder's or lodger's family, # including their children. other_occupier = ~head_family & ~sharer & occupier + # Reg 13D(3)(a): a couple, here the claimant and partner of an + # occupier's family, has one bedroom; (b): every other occupier aged + # 16 or over has their own. Each member of a couple counts as half. + couple_member = person("is_claimant_or_partner", period) & person.benunit( + "is_couple", period + ) + occupier_rooms = (other_occupier & aged_16_or_over) * where( + couple_member, 0.5, 1 + ) is_head_family = benunit.any(person("is_household_head", period)) other_occupiers = is_head_family * benunit.max( - person.household.sum(other_occupier & aged_16_or_over) + person.household.sum(occupier_rooms) ) # Reg 13D(3)(c)-(e): the occupiers' children, the claimant's own and # other families', share rooms with each other. From 084664c5cdeaaaa2293ffc162fbf464fe858a6ad Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 2 Oct 2026 01:07:27 -0400 Subject: [PATCH 4/8] Exclude a child placed for adoption from Tax-Free Childcare Childcare Payments (Eligibility) Regs 2015 reg 4(2)(d): no one is responsible for a child placed for adoption by an adoption agency in the home of a person proposing to adopt them. The new is_placed_for_adoption input is documented for each scheme it touches: Universal Credit and Pension Credit treat the adopter as responsible (UC reg 4A(1)(c); SPC Sch IIA para 4(3)(c)); HB, the legacy schemes and English pensioner CTR do not count the child in the household; CTC's rule 4 case B depends on local authority payments and is not modelled. Changelog covers the HB occupier couple rule too. Found by the first review attempt's probes. Co-Authored-By: Claude Opus 5.5 --- changelog.d/2011.fixed.md | 2 +- .../tax_free_childcare_qualifying_child.yaml | 11 +++++++++++ .../tax_free_childcare_qualifying_child.py | 11 ++++++++++- .../demographic/is_placed_for_adoption.py | 18 +++++++++++++++--- 4 files changed, 37 insertions(+), 5 deletions(-) diff --git a/changelog.d/2011.fixed.md b/changelog.d/2011.fixed.md index 050a5351d..2d7859acd 100644 --- a/changelog.d/2011.fixed.md +++ b/changelog.d/2011.fixed.md @@ -1 +1 @@ -- Count the children of the household head's non-dependants (Universal Credit, UC Regs 2013 Sch 4 paras 9-10) and of non-dependants, boarders and lodgers (Housing Benefit, HB Regs 2006 reg 13D(12)) in the household head's LHA size criteria, sharing rooms with the head's own children. Give foster children no bedroom of their own, and foster parents, adopters with a child placed, and households with a non-resident overnight carer an additional bedroom (UC Sch 4 para 12; HB reg 13D(3A)-(3B)), with new inputs `is_placed_for_adoption`, `is_approved_foster_parent_without_placement` and `has_non_resident_overnight_carer`. Except foster parents from the shared accommodation rate (UC para 29(9A); HB "young individual"), and count armed forces independence payment in the UC para 29(5) exception. +- Count the children of the household head's non-dependants (Universal Credit, UC Regs 2013 Sch 4 paras 9-10) and of non-dependants, boarders and lodgers (Housing Benefit, HB Regs 2006 reg 13D(12)) in the household head's LHA size criteria, sharing rooms with the head's own children. Give foster children no bedroom of their own, and foster parents, adopters with a child placed, and households with a non-resident overnight carer an additional bedroom (UC Sch 4 para 12; HB reg 13D(3A)-(3B)), with new inputs `is_placed_for_adoption`, `is_approved_foster_parent_without_placement` and `has_non_resident_overnight_carer`. Except foster parents from the shared accommodation rate (UC para 29(9A); HB "young individual"), and count armed forces independence payment in the UC para 29(5) exception. Give an occupier couple from another family one Housing Benefit bedroom (HB reg 13D(3)(a)). A child placed for adoption leaves the legacy household (HB reg 21(3), IS reg 16(4), JSA reg 78(4), ESA reg 156(5)) and is not a Tax-Free Childcare qualifying child (Childcare Payments (Eligibility) Regs 2015 reg 4(2)(d)). diff --git a/policyengine_uk/tests/policy/baseline/gov/hmrc/tax_free_childcare/tax_free_childcare_qualifying_child.yaml b/policyengine_uk/tests/policy/baseline/gov/hmrc/tax_free_childcare/tax_free_childcare_qualifying_child.yaml index 7c98bbea9..30daa36fe 100644 --- a/policyengine_uk/tests/policy/baseline/gov/hmrc/tax_free_childcare/tax_free_childcare_qualifying_child.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/hmrc/tax_free_childcare/tax_free_childcare_qualifying_child.yaml @@ -25,6 +25,17 @@ output: tax_free_childcare_qualifying_child: false +- name: A child placed for adoption is not a qualifying child + period: 2025 + input: + tax_free_childcare_child_age_eligible: true + is_parent: false + is_looked_after_by_local_authority: false + is_placed_for_adoption: true + output: + # Childcare Payments (Eligibility) Regs 2015 reg 4(2)(d). + tax_free_childcare_qualifying_child: false + - name: Age-ineligible child is not qualifying period: 2025 input: diff --git a/policyengine_uk/variables/gov/hmrc/tax_free_childcare/conditions/tax_free_childcare_qualifying_child.py b/policyengine_uk/variables/gov/hmrc/tax_free_childcare/conditions/tax_free_childcare_qualifying_child.py index 0e7ecdb29..da4963733 100644 --- a/policyengine_uk/variables/gov/hmrc/tax_free_childcare/conditions/tax_free_childcare_qualifying_child.py +++ b/policyengine_uk/variables/gov/hmrc/tax_free_childcare/conditions/tax_free_childcare_qualifying_child.py @@ -21,4 +21,13 @@ def formula(person, period, parameters): "is_looked_after_by_local_authority", period, ) - return meets_age_condition & ~is_parent & ~looked_after_by_local_authority + # Childcare Payments (Eligibility) Regs 2015 reg 4(2)(c)-(d): no one is + # responsible for a child looked after by a local authority, or placed + # for adoption in the home of a person proposing to adopt them. + placed_for_adoption = person("is_placed_for_adoption", period) + return ( + meets_age_condition + & ~is_parent + & ~looked_after_by_local_authority + & ~placed_for_adoption + ) diff --git a/policyengine_uk/variables/household/demographic/is_placed_for_adoption.py b/policyengine_uk/variables/household/demographic/is_placed_for_adoption.py index 533c79119..eebe11ef2 100644 --- a/policyengine_uk/variables/household/demographic/is_placed_for_adoption.py +++ b/policyengine_uk/variables/household/demographic/is_placed_for_adoption.py @@ -12,9 +12,17 @@ class is_placed_for_adoption(Variable): "leave is_looked_after_by_local_authority false: under Universal " "Credit the adopter is responsible for the child (UC Regs 2013 reg " "4A(1)(c)) and satisfies the foster parent condition for an " - "additional bedroom (Sch 4 para 12(4)(b)); under Housing Benefit and " - "the other legacy schemes the child is not a member of the " - "claimant's household (HB Regs 2006 reg 21(3)(b)-(c))." + "additional bedroom (Sch 4 para 12(4)(b)), and Pension Credit treats " + "them as the adopter's responsibility too (SPC Regs 2002 Sch IIA " + "para 4(3)(c)). Under Housing Benefit, the other legacy schemes and " + "council tax reduction the child is not a member of the claimant's " + "household (HB Regs 2006 reg 21(3)(b)-(c); CTR (England) prescribed " + "requirements reg 8(2)(b)-(c)), and no one is responsible for them " + "for Tax-Free Childcare (Childcare Payments (Eligibility) Regs 2015 " + "reg 4(2)(d)). Child Tax Credit excludes a child placed for adoption " + "only while the local authority pays for their accommodation or " + "maintenance (CTC Regs 2002 reg 3, rule 4 case B), which is not " + "modelled." ) definition_period = YEAR default_value = False @@ -22,4 +30,8 @@ class is_placed_for_adoption(Variable): "https://www.legislation.gov.uk/uksi/2013/376/regulation/4A", "https://www.legislation.gov.uk/uksi/2013/376/schedule/4/paragraph/12", "https://www.legislation.gov.uk/uksi/2006/213/regulation/21", + "https://www.legislation.gov.uk/uksi/2012/2885/regulation/8", + "https://www.legislation.gov.uk/uksi/2015/448/regulation/4", + "https://www.legislation.gov.uk/uksi/2002/1792/schedule/IIA", + "https://www.legislation.gov.uk/uksi/2002/2007/regulation/3", ) From 9311e4e998679cfc2cb3e153e27971e30571989b Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 2 Oct 2026 02:44:40 -0400 Subject: [PATCH 5/8] Address review r1: foster-child age, half rooms, date gate, independent test predicates - HB occupier couple: count the half rooms only when both members are counted, so a benefit unit flagged as a couple without two adults no longer produces a fractional bedroom (and an enum error downstream). - UC: read "child" as under 18 for foster children throughout (is_lha_foster_child; parameter gov.dwp.LHA.foster_child_age_limit): a looked-after 16- or 17-year-old placed with the renter has no room of their own, and their overnight care counts under para 12(A1)(c). - Overnight care beyond the renter or HB claimant and partner applies from 1 April 2017 (SI 2017/213; parameter overnight_care_beyond_claimant). - youngest_child_age_for_legacy_benefits leaves out a child placed with the family (IS reg 16(4)). - Property tests derive the added person's status from the inputs (UC reg 5, Child Benefit QYP, looked after under 18) instead of the model, bias the generator towards looked-after young people, and give the added person overnight care in the reference property. - YAML: 13 new cases pinning the reviewer's surviving mutants and probes, a case with an inconsistent couple flag, and a 2016 date-gate case; the fostering-couple case now uses ages that detect counting the foster child; corrected citations. - Documentation: Scottish working-age CTR adoption gap, Scottish devolved disability benefits, HB 13D(3A)(a)(iii) reading, reg 21(3)(a) and s.22C, and the overnight-carer and adoption inputs. Co-Authored-By: Claude Opus 5.5 --- changelog.d/2011.fixed.md | 2 +- .../gov/dwp/LHA/foster_child_age_limit.yaml | 13 + .../gov/dwp/LHA/overnight_care_benefits.yaml | 2 +- .../LHA/overnight_care_beyond_claimant.yaml | 14 + ...ared_accommodation_exception_benefits.yaml | 2 +- ...lies_children_and_additional_bedrooms.yaml | 451 +++++++++++++++++- .../family/LHA_young_person_bedroom.yaml | 8 +- ...est_lha_bedroom_young_people_properties.py | 128 +++-- .../gov/dwp/LHA_additional_bedrooms.py | 15 +- .../variables/gov/dwp/LHA_allowed_bedrooms.py | 7 +- ...housing_benefit_LHA_additional_bedrooms.py | 28 +- .../housing_benefit_LHA_allowed_bedrooms.py | 16 +- ...hild_or_young_person_placed_with_family.py | 16 +- .../variables/gov/dwp/is_lha_foster_child.py | 36 ++ .../dwp/is_non_dependant_of_household_head.py | 10 +- ...ha_renter_meets_foster_parent_condition.py | 20 +- .../dwp/meets_lha_overnight_care_condition.py | 7 +- .../youngest_child_age_for_legacy_benefits.py | 9 +- .../has_non_resident_overnight_carer.py | 10 +- .../is_looked_after_by_local_authority.py | 7 +- .../demographic/is_placed_for_adoption.py | 41 +- 21 files changed, 731 insertions(+), 111 deletions(-) create mode 100644 policyengine_uk/parameters/gov/dwp/LHA/foster_child_age_limit.yaml create mode 100644 policyengine_uk/parameters/gov/dwp/LHA/overnight_care_beyond_claimant.yaml create mode 100644 policyengine_uk/variables/gov/dwp/is_lha_foster_child.py diff --git a/changelog.d/2011.fixed.md b/changelog.d/2011.fixed.md index 2d7859acd..9c8e9ebca 100644 --- a/changelog.d/2011.fixed.md +++ b/changelog.d/2011.fixed.md @@ -1 +1 @@ -- Count the children of the household head's non-dependants (Universal Credit, UC Regs 2013 Sch 4 paras 9-10) and of non-dependants, boarders and lodgers (Housing Benefit, HB Regs 2006 reg 13D(12)) in the household head's LHA size criteria, sharing rooms with the head's own children. Give foster children no bedroom of their own, and foster parents, adopters with a child placed, and households with a non-resident overnight carer an additional bedroom (UC Sch 4 para 12; HB reg 13D(3A)-(3B)), with new inputs `is_placed_for_adoption`, `is_approved_foster_parent_without_placement` and `has_non_resident_overnight_carer`. Except foster parents from the shared accommodation rate (UC para 29(9A); HB "young individual"), and count armed forces independence payment in the UC para 29(5) exception. Give an occupier couple from another family one Housing Benefit bedroom (HB reg 13D(3)(a)). A child placed for adoption leaves the legacy household (HB reg 21(3), IS reg 16(4), JSA reg 78(4), ESA reg 156(5)) and is not a Tax-Free Childcare qualifying child (Childcare Payments (Eligibility) Regs 2015 reg 4(2)(d)). +- Count the children of the household head's non-dependants (Universal Credit, UC Regs 2013 Sch 4 paras 9-10) and of non-dependants, boarders and lodgers (Housing Benefit, HB Regs 2006 reg 13D(12)) in the household head's LHA size criteria, sharing rooms with the head's own children. Give foster children no bedroom of their own, and foster parents, adopters with a child placed, and households with a non-resident overnight carer an additional bedroom (UC Sch 4 para 12; HB reg 13D(3A)-(3B)), with new inputs `is_placed_for_adoption`, `is_approved_foster_parent_without_placement` and `has_non_resident_overnight_carer`. Except foster parents from the shared accommodation rate (UC para 29(9A); HB "young individual"), and count armed forces independence payment in the UC para 29(5) exception. Give an occupier couple from another family one Housing Benefit bedroom (HB reg 13D(3)(a)). A child placed for adoption leaves the legacy household (HB reg 21(3), IS reg 16(4), JSA reg 78(4), ESA reg 156(5)) and is not a Tax-Free Childcare qualifying child (Childcare Payments (Eligibility) Regs 2015 reg 4(2)(d)). Treat a person under 18 looked after by a local authority and placed with the renter as the renter's foster child throughout the Universal Credit size criteria (`is_lha_foster_child`). Apply the 2017 extension of the overnight care bedroom beyond the renter or claimant from April 2017. Leave a child placed with the family out of the Income Support youngest-child test (IS reg 16(4)). diff --git a/policyengine_uk/parameters/gov/dwp/LHA/foster_child_age_limit.yaml b/policyengine_uk/parameters/gov/dwp/LHA/foster_child_age_limit.yaml new file mode 100644 index 000000000..f7c5c478a --- /dev/null +++ b/policyengine_uk/parameters/gov/dwp/LHA/foster_child_age_limit.yaml @@ -0,0 +1,13 @@ +description: Age below which a child looked after by a local authority and placed with a renter is a foster child, making the renter a foster parent, in the Universal Credit size criteria. +values: + 2013-04-29: 18 +metadata: + unit: year + label: LHA foster child age limit + reference: + - title: Universal Credit Regulations 2013 reg 2, "foster parent" (a child placed under the Care Planning, Placement and Case Review (England) Regulations 2010) + href: https://www.legislation.gov.uk/uksi/2013/376/regulation/2 + - title: Universal Credit Regulations 2013 Sch 4 para 9(3), "foster child" + href: https://www.legislation.gov.uk/uksi/2013/376/schedule/4/paragraph/9 + - title: Children Act 1989 s.105(1), "child" means a person under the age of eighteen + href: https://www.legislation.gov.uk/ukpga/1989/41/section/105 diff --git a/policyengine_uk/parameters/gov/dwp/LHA/overnight_care_benefits.yaml b/policyengine_uk/parameters/gov/dwp/LHA/overnight_care_benefits.yaml index 4e2353ce1..a3b58e7eb 100644 --- a/policyengine_uk/parameters/gov/dwp/LHA/overnight_care_benefits.yaml +++ b/policyengine_uk/parameters/gov/dwp/LHA/overnight_care_benefits.yaml @@ -1,4 +1,4 @@ -description: Disability benefits whose recipients, if non-resident carers regularly stay overnight to care for them, give the household an additional bedroom in the LHA size criteria. +description: Disability benefits whose recipients, if non-resident carers regularly stay overnight to care for them, give an additional bedroom in the LHA size criteria. The law also lists the Scottish devolved equivalents (child disability payment, adult disability payment, Scottish adult disability living allowance, pension age disability payment), which the model has no variables for. values: 2011-04-01: - attendance_allowance diff --git a/policyengine_uk/parameters/gov/dwp/LHA/overnight_care_beyond_claimant.yaml b/policyengine_uk/parameters/gov/dwp/LHA/overnight_care_beyond_claimant.yaml new file mode 100644 index 000000000..d8628e728 --- /dev/null +++ b/policyengine_uk/parameters/gov/dwp/LHA/overnight_care_beyond_claimant.yaml @@ -0,0 +1,14 @@ +description: Whether the overnight care additional bedroom in the LHA size criteria covers people other than the renter or claimant and partner, such as non-dependants, other occupiers and foster children. +values: + 2011-04-01: false + 2017-04-01: true +metadata: + unit: bool + label: LHA overnight care covers the household + reference: + - title: Housing Benefit and Universal Credit (Size Criteria) (Miscellaneous Amendments) Regulations 2017 (SI 2017/213) regs 4 and 6 + href: https://www.legislation.gov.uk/uksi/2017/213/made + - title: Universal Credit Regulations 2013 Sch 4 para 12(A1) + href: https://www.legislation.gov.uk/uksi/2013/376/schedule/4/paragraph/12 + - title: Housing Benefit Regulations 2006 reg 13D(3A)(a) + href: https://www.legislation.gov.uk/uksi/2006/213/regulation/13D diff --git a/policyengine_uk/parameters/gov/dwp/LHA/shared_accommodation_exception_benefits.yaml b/policyengine_uk/parameters/gov/dwp/LHA/shared_accommodation_exception_benefits.yaml index 96241d625..3de4aab0b 100644 --- a/policyengine_uk/parameters/gov/dwp/LHA/shared_accommodation_exception_benefits.yaml +++ b/policyengine_uk/parameters/gov/dwp/LHA/shared_accommodation_exception_benefits.yaml @@ -1,4 +1,4 @@ -description: Disability benefits whose recipients under 35 are excepted from the shared accommodation rate. +description: Disability benefits whose recipients under 35 are excepted from the shared accommodation rate. The law also lists the Scottish devolved equivalents (child disability payment, adult disability payment, Scottish adult disability living allowance), which the model has no variables for. values: 2013-04-29: - attendance_allowance diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_other_families_children_and_additional_bedrooms.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_other_families_children_and_additional_bedrooms.yaml index fb3d46a03..4281a5322 100644 --- a/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_other_families_children_and_additional_bedrooms.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_other_families_children_and_additional_bedrooms.yaml @@ -68,7 +68,8 @@ # 4 bedrooms. The daughter's own entitlement counts her and her child. LHA_allowed_bedrooms: [4, 2] LHA_category: [E, C] - # HB: the same four occupiers' categories (reg 13D(3)(a), (b), (e)). + # HB: the claimant, the daughter and the two children: the same four + # occupiers' categories (reg 13D(3)(b), (e)). housing_benefit_LHA_allowed_bedrooms: [4, 2] housing_benefit_LHA_category: [E, C] @@ -138,7 +139,8 @@ # under 10 (10(1)(d)): 3 bedrooms, category D. LHA_allowed_bedrooms: [3, 2] LHA_category: [D, C] - # HB: reg 13D(3)(a), (b), (d). + # HB: the claimant, the daughter (reg 13D(3)(b)) and the two + # grandchildren ((d)). housing_benefit_LHA_allowed_bedrooms: [3, 2] housing_benefit_LHA_category: [D, C] @@ -230,10 +232,12 @@ tenure_type: RENT_PRIVATELY brma: MAIDSTONE output: - # A joint tenant outside the claimant's household is not an occupier - # (HB reg 13D(12)), nor their household (LHA Guidance Manual paras 2.031 - # and 2.093); under UC they are liable for their occupation (para - # 9(2)(d)). Each joint tenant counts their own family. + # A joint tenant outside the claimant's household is not an occupier (HB + # reg 13D(12)), and in the private sector each joint tenant's size + # criteria count only their own household (LHA Guidance Manual para + # 2.093; HB circular A21/2013 para 25). Under UC they are liable for + # their occupation (para 9(2)(d)), so neither they nor their children are + # in the other tenant's extended benefit unit. LHA_allowed_bedrooms: [1, 2] housing_benefit_LHA_allowed_bedrooms: [1, 2] @@ -331,10 +335,10 @@ age: 36 is_parent: true son: - age: 5 + age: 12 is_male: true foster_daughter: - age: 3 + age: 11 is_male: false is_looked_after_by_local_authority: true benunits: @@ -349,8 +353,9 @@ output: is_claimant_or_partner: [true, true, false, false] # UC: the couple, their son (para 10(1)(f)), and the foster parent's - # additional bedroom (para 12(9)(b)): 3 bedrooms. The foster daughter - # does not share with the son as a child of the extended benefit unit. + # additional bedroom (para 12(9)(b)): 3 bedrooms. Counted as a child of + # the extended benefit unit, the foster daughter (11) could not share + # with the son (12) and would add a fourth. LHA_allowed_bedrooms: 3 LHA_category: D # HB: the couple, the son (reg 13D(3)(e)) and the qualifying parent or @@ -486,7 +491,7 @@ housing_benefit_LHA_category: C uc_housing_costs_element: 10_400 -- name: Overnight care from a partner who lives in the home gives no additional bedroom +- name: A disability benefit without a non-resident overnight carer gives no additional bedroom period: 2026 input: people: @@ -664,3 +669,427 @@ # forces independence payment (reg 2). is_lha_shared_accommodation_rate_specified_renter: false LHA_category: B + +- name: A lodger flagged as a couple without a partner still counts as one occupier + period: 2026 + input: + people: + householder: + age: 55 + is_household_head: true + lodger: + age: 40 + rent_paid_as_lodger: 3_000 + benunits: + householder_family: + members: [householder] + lodger_family: + members: [lodger] + relation_type: COUPLE + households: + home: + members: [householder, lodger] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + # HB: the lodger is "a person who is not a child" (reg 13D(3)(b)); the + # couple rule (a) needs two members, so no half room: 2 bedrooms. The + # lodger, entitled to one bedroom without exclusive use of the + # accommodation, has the shared rate (reg 13D(2)(a)(ii)). + housing_benefit_LHA_allowed_bedrooms: [2, 1] + housing_benefit_LHA_category: [C, A] + +- name: A looked-after 17-year-old not in education is the renter's foster child under Universal Credit + period: 2026 + input: + people: + renter: + age: 40 + is_household_head: true + young_person: + age: 17 + current_education: NOT_IN_EDUCATION + is_looked_after_by_local_authority: true + benunits: + family: + members: [renter, young_person] + households: + home: + members: [renter, young_person] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + # UC: a person under 18 placed with the renter by a local authority + # makes the renter a foster parent (reg 2) and is their foster child + # (para 9(2)(c), 9(3); see is_lha_foster_child): no bedroom of their own, + # one foster room: 2. (Read as under 16, they would be a non-dependant + # with a bedroom and there would be no foster room: also 2.) + is_lha_foster_child: [false, true] + LHA_additional_bedrooms: 1 + LHA_allowed_bedrooms: 2 + # HB: not a "young person" (reg 19), so reg 21(3) does not apply: an + # occupier aged 16 or over with a bedroom, and no qualifying parent or + # carer room: 2. + is_child_or_young_person_placed_with_family: [false, false] + housing_benefit_LHA_additional_bedrooms: 0 + housing_benefit_LHA_allowed_bedrooms: 2 + +- name: A looked-after 17-year-old placed with a non-dependant + period: 2026 + input: + people: + renter: + age: 50 + is_household_head: true + daughter: + age: 35 + is_male: false + young_person: + age: 17 + current_education: NOT_IN_EDUCATION + is_looked_after_by_local_authority: true + benunits: + renter_family: + members: [renter] + daughter_family: + members: [daughter, young_person] + households: + home: + members: [renter, daughter, young_person] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + # UC: for the renter, the 17-year-old is neither a child nor a qualifying + # young person, so para 9(2)(g) does not exclude them, and they are not + # the renter's foster child: renter, daughter and young person, 3. The + # daughter's own size criteria: herself and the foster room, 2. + LHA_allowed_bedrooms: [3, 2] + # HB: not a "young person" (reg 19), so an occupier: 3. The daughter's + # own: 1 + the 17-year-old (13D(3)(b)) = 2; no carer room, since reg + # 21(3) does not apply. + housing_benefit_LHA_allowed_bedrooms: [3, 2] + +- name: A foster child who needs overnight care gives the overnight and the foster bedrooms + period: 2026 + input: + people: + foster_parent: + age: 40 + is_household_head: true + foster_child: + age: 8 + is_looked_after_by_local_authority: true + dla_sc_middle_plus: true + has_non_resident_overnight_carer: true + benunits: + family: + members: [foster_parent, foster_child] + households: + home: + members: [foster_parent, foster_child] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + # UC para 12(A1)(c), (9)(a)-(b); HB reg 13D(3A)(a)(iv), (3B). + LHA_additional_bedrooms: 2 + LHA_allowed_bedrooms: 3 + housing_benefit_LHA_additional_bedrooms: 2 + housing_benefit_LHA_allowed_bedrooms: 3 + +- name: A looked-after qualifying young person who needs overnight care + period: 2026 + input: + people: + carer: + age: 40 + is_household_head: true + is_parent: true + young_person: + age: 17 + current_education: UPPER_SECONDARY + is_looked_after_by_local_authority: true + dla_sc_middle_plus: true + has_non_resident_overnight_carer: true + benunits: + family: + members: [carer, young_person] + households: + home: + members: [carer, young_person] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + is_qualifying_young_person_for_universal_credit: [false, true] + is_child_or_qualifying_young_person_for_universal_credit: [false, false] + # UC: the young person is the renter's foster child (under 18), so their + # overnight care counts under para 12(A1)(c): foster and overnight rooms, + # 3. + LHA_additional_bedrooms: 2 + LHA_allowed_bedrooms: 3 + # HB: placed under reg 21(3), so not an occupier, but within + # 13D(3A)(a)(iv); with the qualifying parent or carer room, (3B): 3. + housing_benefit_LHA_additional_bedrooms: 2 + housing_benefit_LHA_allowed_bedrooms: 3 + +- name: A lodger who needs overnight care counts for Housing Benefit only + period: 2026 + input: + people: + householder: + age: 60 + is_household_head: true + lodger: + age: 45 + rent_paid_as_lodger: 5_000 + pip_dl: 5_000 + has_non_resident_overnight_carer: true + benunits: + householder_family: + members: [householder] + lodger_family: + members: [lodger] + households: + home: + members: [householder, lodger] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + # UC: the lodger is outside the extended benefit unit (para 9(2)(d)): 1. + # HB: the lodger is an occupier (13D(3)(b)) who requires overnight care + # (13D(3A)(a)(iii)): 3. The lodger's own claim: 1 + carer room = 2. + LHA_allowed_bedrooms: [1, 2] + housing_benefit_LHA_allowed_bedrooms: [3, 2] + +- name: A joint tenant's overnight care counts only for that tenant + period: 2026 + input: + people: + tenant_1: + age: 40 + is_household_head: true + tenant_2: + age: 38 + pip_dl: 5_000 + has_non_resident_overnight_carer: true + benunits: + family_1: + members: [tenant_1] + family_2: + members: [tenant_2] + liable_for_share_of_household_rent: true + households: + home: + members: [tenant_1, tenant_2] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + # UC: the joint tenant is not in the other's extended benefit unit (para + # 9(2)(d)). HB: 13D(3A)(a)(iii) says "a person ... who occupies the + # claimant's dwelling as their home", without the defined term + # "occupiers"; the model applies 13D(12)'s joint-tenant exclusion, as + # private-sector joint tenants' size criteria rest on each tenant's own + # household (HB circular A21/2013 para 25). + LHA_allowed_bedrooms: [1, 2] + housing_benefit_LHA_allowed_bedrooms: [1, 2] + +- name: A boarder couple with a child counts as two Housing Benefit bedrooms + period: 2026 + input: + people: + householder: + age: 60 + is_household_head: true + boarder: + age: 35 + rent_paid_as_boarder: 5_000 + boarders_partner: + age: 33 + boarders_child: + age: 4 + benunits: + householder_family: + members: [householder] + boarder_family: + members: [boarder, boarders_partner, boarders_child] + households: + home: + members: [householder, boarder, boarders_partner, boarders_child] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + # HB: the householder, the boarder couple (13D(3)(a)) and the child: 3. + housing_benefit_LHA_allowed_bedrooms: [3, 2] + LHA_allowed_bedrooms: [1, 2] + +- name: A non-dependant's child placed for adoption + period: 2026 + input: + people: + renter: + age: 60 + is_household_head: true + daughter: + age: 30 + is_male: false + child: + age: 5 + is_placed_for_adoption: true + benunits: + renter_family: + members: [renter] + daughter_family: + members: [daughter, child] + households: + home: + members: [renter, daughter, child] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + # UC: reg 4A(1)(c) makes the daughter responsible, so the child is in + # the renter's extended benefit unit: 3. The daughter's own: herself, the + # child and the adopter's room, 3. + LHA_allowed_bedrooms: [3, 3] + # HB: following DWP, a child placed with anyone in the household is not + # an occupier: 2. The daughter's own: herself and the qualifying parent + # or carer room, 2. + housing_benefit_LHA_allowed_bedrooms: [2, 2] + +- name: Five or more bedrooms map to the four-bedroom category + period: 2026 + input: + people: + renter: + age: 50 + is_household_head: true + is_approved_foster_parent_without_placement: true + non_dependant_1: + age: 30 + non_dependant_2: + age: 29 + non_dependant_3: + age: 40 + benunits: + renter_family: + members: [renter] + non_dependant_family_1: + members: [non_dependant_1, non_dependant_2] + non_dependant_family_2: + members: [non_dependant_3] + households: + home: + members: [renter, non_dependant_1, non_dependant_2, non_dependant_3] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + # UC: the renter, three non-dependants and the foster room: 5, capped at + # category E (para 26). HB: the claimant, the couple (13D(3)(a)), the + # other non-dependant and the carer room: 4, E. + LHA_allowed_bedrooms: [5, 1, 1] + LHA_category: [E, B, B] + housing_benefit_LHA_allowed_bedrooms: [4, 1, 1] + housing_benefit_LHA_category: [E, B, B] + +- name: Before April 2017 a non-dependant's overnight care gave no additional bedroom + period: 2016 + input: + people: + renter: + age: 58 + is_household_head: true + son: + age: 30 + pip_dl: 5_000 + has_non_resident_overnight_carer: true + benunits: + renter_family: + members: [renter] + son_family: + members: [son] + households: + home: + members: [renter, son] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + # UC Sch 4 para 12(A1)(b) and HB reg 13D(3A)(a)(iii) came in on 1 April + # 2017 (SI 2017/213); before then only the renter or claimant and + # partner counted. The son's own claim keeps his room. + LHA_additional_bedrooms: [0, 1] + LHA_allowed_bedrooms: [2, 2] + housing_benefit_LHA_additional_bedrooms: [0, 1] + housing_benefit_LHA_allowed_bedrooms: [2, 2] + +- name: A non-dependant's foster child who needs overnight care counts only for the non-dependant + period: 2026 + input: + people: + renter: + age: 60 + is_household_head: true + daughter: + age: 32 + is_male: false + foster_child: + age: 6 + is_looked_after_by_local_authority: true + dla_sc_middle_plus: true + has_non_resident_overnight_carer: true + benunits: + renter_family: + members: [renter] + daughter_family: + members: [daughter, foster_child] + households: + home: + members: [renter, daughter, foster_child] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + # UC: the foster child is in no one's extended benefit unit but the + # foster parent's (para 9(2)(g); 12(A1)(c)), so the renter gets no + # overnight room: 2. The daughter: herself, the foster room and the + # overnight room, 3. HB: not an occupier of the renter's dwelling (model + # follows DWP); the daughter's own: herself, the carer room and the + # overnight room ((3A)(a)(iv)), 3. + LHA_additional_bedrooms: [0, 2] + LHA_allowed_bedrooms: [2, 3] + housing_benefit_LHA_additional_bedrooms: [0, 2] + housing_benefit_LHA_allowed_bedrooms: [2, 3] + +- name: A claimant who is looked after gives no foster room + period: 2026 + input: + people: + claimant: + age: 19 + is_household_head: true + is_looked_after_by_local_authority: true + benunits: + family: + members: [claimant] + households: + home: + members: [claimant] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + # The foster parent condition needs a child placed with the renter, not + # the renter's own status (UC reg 2; HB reg 2(1)). + is_lha_foster_child: false + lha_renter_meets_foster_parent_condition: false + LHA_additional_bedrooms: 0 + is_housing_benefit_qualifying_parent_or_carer: false + housing_benefit_LHA_additional_bedrooms: 0 diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_young_person_bedroom.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_young_person_bedroom.yaml index 16cd81fe7..315a51ead 100644 --- a/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_young_person_bedroom.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_young_person_bedroom.yaml @@ -143,8 +143,12 @@ is_child_or_qualifying_young_person_for_universal_credit: [false, false] # Not under para 10(1)(b), and not a non-dependant (para 9(2)(g)), so no # bedroom of their own. The carer they are placed with is a foster parent - # (reg 2), so has one additional bedroom (para 12(4)(a), (9)(b)): 2 - # bedrooms, category C. + # (reg 2: a person with whom a child is placed under the care planning + # regulations, which place children under 18), so has one additional + # bedroom (para 12(4)(a), (9)(b)): 2 bedrooms, category C. The model reads + # "child" there as under 18 (see is_lha_foster_child; reg 91(2)(b)-(d) + # also speak of foster parents of qualifying young persons). Read as under + # 16 (WRA 2012 s.40), there would be no foster room and 1 bedroom. LHA_additional_bedrooms: 1 LHA_allowed_bedrooms: 2 LHA_category: C diff --git a/policyengine_uk/tests/test_lha_bedroom_young_people_properties.py b/policyengine_uk/tests/test_lha_bedroom_young_people_properties.py index 3bd022adc..65d3b70cc 100644 --- a/policyengine_uk/tests/test_lha_bedroom_young_people_properties.py +++ b/policyengine_uk/tests/test_lha_bedroom_young_people_properties.py @@ -14,14 +14,15 @@ claimant or partner, their family gains one Housing Benefit bedroom unless the person is placed with it as a foster child (HB reg 21(3)), and one Universal Credit bedroom unless they are a qualifying young person no - one is responsible for (para 9(2)(g)); a family they are placed with as a - foster child gains the foster parent's (UC, para 12) or qualifying parent - or carer's (HB, 13D(3A)(b)) bedroom if it did not already have it. The - household head's family also gains one bedroom under both schemes if the - person joins a non-dependant's family (UC: unless no one is responsible - for them), and one Housing Benefit bedroom if they join a boarder's or - lodger's family (HB: unless placed with it as a foster child). No other - family's bedrooms change. + one is responsible for (para 9(2)(g)) or the family's foster child (under + 18, para 9(2)(c)); a family they are placed with as a foster child gains + the foster parent's (UC, para 12) or qualifying parent or carer's (HB, + 13D(3A)(b)) bedroom if it did not already have it. The household head's + family also gains one bedroom under both schemes if the person joins a + non-dependant's family (UC: unless no one is responsible for them; HB: + unless placed with it), and one Housing Benefit bedroom if they join a + boarder's or lodger's family (unless placed with it). No other family's + bedrooms change. 3. Children: adding a child under 16 who is neither fostered nor placed for adoption to any family never lowers any family's bedrooms under either scheme and raises each by at most one. @@ -32,12 +33,19 @@ child placed with another family is not in the household head's extended benefit unit (UC para 9(2)(g)) and, following DWP, not an occupier (HB; LHA Guidance Manual para 2.033). -5. Reference: every family's bedrooms, and its additional bedrooms, equal an - independent count of the size criteria: +5. Reference: every family's bedrooms, and its additional bedrooms, equal a + count of the size criteria made by the test itself. The added person's + status comes from the test's own predicates on the inputs (UC reg 5 + qualifying young person, the Child Benefit qualifying young person for + HB reg 19, looked after and under 18 for a foster child), not from the + model, and children's rooms come from a brute-force pairing. The count + applies the same legal readings as the model, including its judgment + calls (see the PR), so it checks the implementation of those readings, + not the readings themselves: - one for the claimant or couple; - one for each other member aged 16 or over (UC: except a qualifying - young person no one is responsible for; HB: except one placed with the - family as a foster child); + young person no one is responsible for and a foster child under 18; + HB: except one placed with the family as a foster child); - for the household head's family, one for each person aged 16 or over in a non-dependant's family (and, for HB, in a boarder's or lodger's family), except one no one is responsible for (UC) or placed with that @@ -71,7 +79,7 @@ suppress_health_check=[HealthCheck.too_slow, HealthCheck.data_too_large], ) ROLES = ["sharer", "boarder", "lodger", "non_dependant"] -EDUCATION = ["NOT_IN_EDUCATION", "UPPER_SECONDARY", "TERTIARY"] +EDUCATION = ["NOT_IN_EDUCATION", "UPPER_SECONDARY", "UPPER_SECONDARY", "TERTIARY"] KINDS = ["own", "own", "own", "foster", "adopted"] OVERNIGHT = st.sampled_from([False, False, False, True]) @@ -101,7 +109,7 @@ def household(draw): @st.composite def young_person(draw): - return dict( + person = dict( age=draw(st.integers(16, 19)), is_male=draw(st.booleans()), current_education=draw(st.sampled_from(EDUCATION)), @@ -109,9 +117,21 @@ def young_person(draw): is_before_universal_credit_qualifying_young_person_terminal_date=draw( st.booleans() ), - is_looked_after_by_local_authority=draw(st.booleans()), - receives_benefits_in_own_right=draw(st.booleans()), + is_looked_after_by_local_authority=draw(st.sampled_from([False, True, True])), + receives_benefits_in_own_right=draw(st.sampled_from([False, False, True])), ) + if draw(OVERNIGHT): + person["dla_sc_middle_plus"] = True + person["has_non_resident_overnight_carer"] = True + return person + + +def without_overnight_care(person): + return { + k: v + for k, v in person.items() + if k not in ("dla_sc_middle_plus", "has_non_resident_overnight_carer") + } @st.composite @@ -244,24 +264,54 @@ def fosters(fam): ) -def flags(sim, situation, pid): - """The added person's attributes as the model determines them.""" - index = list(situation["people"]).index(pid) +def in_qualifying_education(p, age_limit_for_entry=19): + """Full-time non-advanced education, entered before 19.""" + return p["current_education"] == "UPPER_SECONDARY" and ( + p["age"] < age_limit_for_entry + or p["age_started_or_accepted_current_education_or_training"] + < age_limit_for_entry + ) - def value(variable): - return bool(sim.calculate(variable, YEAR)[index]) - qualifying = value("is_qualifying_young_person_for_universal_credit") - responsible = value("is_child_or_qualifying_young_person_for_universal_credit") +def uc_qualifying_young_person(p): + """UC Regs 2013 reg 5: aged 16 to 19, in non-advanced education entered + before 19, before the terminal date if 19, and not receiving benefits in + their own right.""" + return ( + 16 <= p["age"] < 20 + and in_qualifying_education(p) + and ( + p["age"] < 19 + or p["is_before_universal_credit_qualifying_young_person_terminal_date"] + ) + and not p["receives_benefits_in_own_right"] + ) + + +def child_benefit_qualifying_young_person(p): + """SSCBA 1992 s.142 and the Child Benefit (General) Regulations 2006, as + HB reg 19's "young person": aged 16 to 19 in non-advanced education + entered before 19, and not receiving benefits in their own right.""" + return ( + 16 <= p["age"] < 20 + and in_qualifying_education(p) + and not p["receives_benefits_in_own_right"] + ) + + +def flags(p): + """The added person's status, from the inputs alone.""" + looked_after = p.get("is_looked_after_by_local_authority", False) return dict( - # A qualifying young person no one is responsible for (para 9(2)(g)). - unclaimed=qualifying and not responsible, + # A qualifying young person no one is responsible for (UC para + # 9(2)(g); reg 4(6)(a)). + unclaimed=looked_after and uc_qualifying_young_person(p), + # The family's foster child: looked after and under 18 (UC reg 2, + # "foster parent"; para 9(3)). + fostered=looked_after and p["age"] < 18, # Placed with the family by a local authority (HB reg 21(3)). - placed=value("is_child_or_young_person_placed_with_family"), - # A child under 18 looked after by a local authority is placed with - # a foster parent (UC Regs 2013 reg 2). - fostered=value("is_looked_after_by_local_authority") - and situation["people"][pid]["age"] < 18, + placed=looked_after and child_benefit_qualifying_young_person(p), + overnight=p.get("has_non_resident_overnight_carer", False), ) @@ -283,17 +333,18 @@ def test_adding_a_person_aged_16_to_19_never_lowers_bedrooms(case, supply_roles) @given(scenario()) def test_exact_effect_of_adding_a_person_aged_16_to_19(case): population, target, person = case + person = without_overnight_care(person) before, keys = build(population) after, _ = build(population, (target, person)) _, uc_before, hb_before = bedrooms(before) - sim, uc_after, hb_after = bedrooms(after) - added = flags(sim, after, f"h{target[0]}_f{target[1]}_added") + _, uc_after, hb_after = bedrooms(after) + added = flags(person) fam = population[target[0]][target[1]] # 2. Exact effect. expected_uc = np.zeros(len(keys)) expected_hb = np.zeros(len(keys)) t = keys.index(target) - expected_uc[t] += 0 if added["unclaimed"] else 1 + expected_uc[t] += 0 if added["unclaimed"] or added["fostered"] else 1 expected_uc[t] += int(added["fostered"] and not fosters(fam)) expected_hb[t] += 0 if added["placed"] else 1 expected_hb[t] += int(added["placed"] and not fosters(fam)) @@ -347,14 +398,14 @@ def test_bedrooms_match_an_independent_count_of_the_size_criteria(case): hb_additional = np.asarray( sim.calculate("housing_benefit_LHA_additional_bedrooms", YEAR) ) - added = flags(sim, situation, f"h{target[0]}_f{target[1]}_added") + added = flags(person) # 5. Reference count. for b, (h, f) in enumerate(keys): families = population[h] fam = families[f] is_target = (h, f) == target # Own members aged 16 or over who are not the claimant or partner. - uc_rooms = 1 + int(is_target and not added["unclaimed"]) + uc_rooms = 1 + int(is_target and not (added["unclaimed"] or added["fostered"])) hb_rooms = 1 + int(is_target and not added["placed"]) # Children: UC counts the children the family is responsible for # (not foster children); HB counts occupiers (not children placed @@ -366,6 +417,9 @@ def test_bedrooms_match_an_independent_count_of_the_size_criteria(case): uc_overnight = hb_overnight = any(o for _, o in fam["adults"]) or any( c[3] for c in fam["children"] ) + if is_target and added["overnight"]: + uc_overnight |= added["fostered"] or not added["unclaimed"] + hb_overnight = True uc_foster = fosters(fam) or (is_target and added["fostered"]) hb_carer = fosters(fam) or (is_target and added["placed"]) if fam["role"] == "head": @@ -379,6 +433,9 @@ def test_bedrooms_match_an_independent_count_of_the_size_criteria(case): uc_overnight |= any(o for _, o in other["adults"]) or any( c[3] for c in other["children"] if c[2] != "foster" ) + uc_overnight |= ( + joins and added["overnight"] and not added["unclaimed"] + ) if other["role"] in ("non_dependant", "boarder", "lodger"): # HB reg 13D(3)(a): the family's claimant or couple # has one bedroom. @@ -387,6 +444,7 @@ def test_bedrooms_match_an_independent_count_of_the_size_criteria(case): hb_overnight |= any(o for _, o in other["adults"]) or any( c[3] for c in other["children"] if c[2] == "own" ) + hb_overnight |= joins and added["overnight"] and not added["placed"] expected_uc_additional = int(uc_overnight) + int(uc_foster) expected_hb_additional = int(hb_overnight) + int(hb_carer) assert uc_additional[b] == expected_uc_additional diff --git a/policyengine_uk/variables/gov/dwp/LHA_additional_bedrooms.py b/policyengine_uk/variables/gov/dwp/LHA_additional_bedrooms.py index 6a9dab2c1..3d580ea58 100644 --- a/policyengine_uk/variables/gov/dwp/LHA_additional_bedrooms.py +++ b/policyengine_uk/variables/gov/dwp/LHA_additional_bedrooms.py @@ -13,6 +13,8 @@ class LHA_additional_bedrooms(Variable): "parent condition (see lha_renter_meets_foster_parent_condition), " "however many children are placed. The extended benefit unit " "includes the household head's non-dependants and their children. " + "Before 1 April 2017 only the renter could meet the overnight care " + "condition. " "The disabled child and disabled person conditions, for children or " "couples who cannot share a bedroom, are not modelled." ) @@ -29,15 +31,16 @@ def formula(benunit, period, parameters): responsible = person( "is_child_or_qualifying_young_person_for_universal_credit", period ) - child = person("is_child_for_universal_credit", period) no_one_responsible = ( - child | person("is_qualifying_young_person_for_universal_credit", period) + person("is_child_for_universal_credit", period) + | person("is_qualifying_young_person_for_universal_credit", period) ) & ~responsible # UC Regs 2013 Sch 4 para 12(A1)(a)-(b): the renter and the members of # their extended benefit unit, which excludes a child or qualifying # young person no one is responsible for (paras 9(1) and 9(2)(g)); # (c): a child for whom the renter meets the foster parent condition. - own = overnight_care & ~(no_one_responsible & ~child) + foster_child = person("is_lha_foster_child", period) + own = overnight_care & (~no_one_responsible | foster_child) # Para 9(1)(c): the household head's non-dependants from other # families, and their children. other = ( @@ -47,6 +50,12 @@ def formula(benunit, period, parameters): ) head_family = benunit.any(person("is_household_head", period)) others = head_family * benunit.max(person.household.sum(other)) + # Before 1 April 2017 (SI 2017/213 reg 6) only the renter could meet + # the overnight care condition. + p = parameters(period).gov.dwp.LHA + renter = person("is_claimant_or_partner", period) + own = where(p.overnight_care_beyond_claimant, own, overnight_care & renter) + others = others * p.overnight_care_beyond_claimant # Para 12(9)(a)-(b): one bedroom for each condition met. overnight_room = benunit.any(own) | (others > 0) foster_room = benunit("lha_renter_meets_foster_parent_condition", period) diff --git a/policyengine_uk/variables/gov/dwp/LHA_allowed_bedrooms.py b/policyengine_uk/variables/gov/dwp/LHA_allowed_bedrooms.py index a89c37115..c210ae2f1 100644 --- a/policyengine_uk/variables/gov/dwp/LHA_allowed_bedrooms.py +++ b/policyengine_uk/variables/gov/dwp/LHA_allowed_bedrooms.py @@ -121,8 +121,11 @@ def formula(benunit, period, parameters): qualifying_young_person = family_member & responsible # Para 10(1)(c) with para 9(2): any other member aged 16 or over is a # non-dependant, unless they are a qualifying young person for whom - # no one is responsible (para 9(2)(g); reg 4(6)). - family_non_dependant = family_member & ~qualifying + # no one is responsible (para 9(2)(g); reg 4(6)) or the renter's + # foster child (para 9(2)(c), 9(3); see is_lha_foster_child). + family_non_dependant = ( + family_member & ~qualifying & ~person("is_lha_foster_child", period) + ) family_rooms = benunit.sum(qualifying_young_person | family_non_dependant) # Para 9(1)(c) and 9(2): people of other families in the household # who are non-dependants of the household head's family. Para 9(2)(g) diff --git a/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_additional_bedrooms.py b/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_additional_bedrooms.py index 5c9d55d1e..d43048fd1 100644 --- a/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_additional_bedrooms.py +++ b/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_additional_bedrooms.py @@ -14,7 +14,9 @@ class housing_benefit_LHA_additional_bedrooms(Variable): "Occupiers outside the family count for the household head's family: " "non-dependants, boarders and lodgers and their children, but not a " "sharer of the rent or a child placed with them as a foster child or " - "for adoption. The definitions require a bedroom in the dwelling for " + "for adoption. Before 1 April 2017 only the claimant and partner " + "counted for overnight care. The definitions require a bedroom in " + "the dwelling for " "the carer or the foster child; the model does not observe the " "dwelling's bedrooms and assumes there is one. Children and couples " "who cannot share a bedroom because of disability are not modelled." @@ -29,10 +31,15 @@ class housing_benefit_LHA_additional_bedrooms(Variable): def formula(benunit, period, parameters): person = benunit.members overnight_care = person("meets_lha_overnight_care_condition", period) - # HB Regs 2006 reg 13D(3A)(a)(iii) and 13D(12): occupiers of other - # families, other than a joint tenant outside the claimant's - # household and a child placed with another family as a foster child - # or for adoption (see housing_benefit_LHA_allowed_bedrooms). + # HB Regs 2006 reg 13D(3A)(a)(iii): "a person ... who occupies the + # claimant's dwelling as their home". (iii) does not use the defined + # term "occupiers", but the model applies 13D(12)'s exclusion of a + # joint tenant outside the claimant's household and, following DWP, + # of a child placed with another family as a foster child or for + # adoption (see housing_benefit_LHA_allowed_bedrooms). A3/2017 frames + # the 2017 extension as a room for carers of a disabled child or + # non-dependant, and A21/2013 para 25 bases private-sector joint + # tenants' size criteria on each tenant's own household. head_family = person.benunit.any(person("is_household_head", period)) sharer = person.benunit("liable_for_share_of_household_rent", period) placed = person("is_child_or_young_person_placed_with_family", period) @@ -41,8 +48,15 @@ def formula(benunit, period, parameters): others = is_head_family * benunit.max(person.household.sum(other)) # Reg 13D(3A)(a)(i)-(iv): the claimant, partner, other members of the # family, and a child or young person for whom the claimant or - # partner is a qualifying parent or carer. - overnight_room = benunit.any(overnight_care) | (others > 0) + # partner is a qualifying parent or carer. Before 1 April 2017 (SI + # 2017/213 reg 4) only the claimant and partner. + p = parameters(period).gov.dwp.LHA + claimant = person("is_claimant_or_partner", period) + own = where( + p.overnight_care_beyond_claimant, overnight_care, overnight_care & claimant + ) + others = others * p.overnight_care_beyond_claimant + overnight_room = benunit.any(own) | (others > 0) # Reg 13D(3A)(b). carer_room = benunit("is_housing_benefit_qualifying_parent_or_carer", period) # Reg 13D(3B): two additional bedrooms where both apply. diff --git a/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_allowed_bedrooms.py b/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_allowed_bedrooms.py index 2891316d1..e11f0cec7 100644 --- a/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_allowed_bedrooms.py +++ b/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_allowed_bedrooms.py @@ -20,7 +20,8 @@ class housing_benefit_LHA_allowed_bedrooms(Variable): "bedroom, such as a young person in full-time education; so do a " "householder's boarder or lodger and a non-dependant, but a sharer " "of the rent does not. A couple, such as a non-dependant and their " - "partner, has one bedroom between them. The children of a non-dependant, boarder or " + "partner, has one bedroom between them. The children of a " + "non-dependant, boarder or " "lodger are occupiers too, and share rooms with the claimant's " "children. A child or young person placed with a family in the " "household as a foster child or for adoption is not an occupier. A " @@ -62,13 +63,12 @@ def formula(benunit, period, parameters): other_occupier = ~head_family & ~sharer & occupier # Reg 13D(3)(a): a couple, here the claimant and partner of an # occupier's family, has one bedroom; (b): every other occupier aged - # 16 or over has their own. Each member of a couple counts as half. - couple_member = person("is_claimant_or_partner", period) & person.benunit( - "is_couple", period - ) - occupier_rooms = (other_occupier & aged_16_or_over) * where( - couple_member, 0.5, 1 - ) + # 16 or over has their own. Each member of a couple counts as half, + # and only where both members are counted, so the halves always pair. + counted = other_occupier & aged_16_or_over + claimant_or_partner = counted & person("is_claimant_or_partner", period) + couple = person.benunit.sum(claimant_or_partner) == 2 + occupier_rooms = counted * where(claimant_or_partner & couple, 0.5, 1) is_head_family = benunit.any(person("is_household_head", period)) other_occupiers = is_head_family * benunit.max( person.household.sum(occupier_rooms) diff --git a/policyengine_uk/variables/gov/dwp/is_child_or_young_person_placed_with_family.py b/policyengine_uk/variables/gov/dwp/is_child_or_young_person_placed_with_family.py index 592130460..8ab5cb8ce 100644 --- a/policyengine_uk/variables/gov/dwp/is_child_or_young_person_placed_with_family.py +++ b/policyengine_uk/variables/gov/dwp/is_child_or_young_person_placed_with_family.py @@ -4,7 +4,7 @@ class is_child_or_young_person_placed_with_family(Variable): value_type = bool entity = Person - label = "Child or young person placed with the family by a local authority or for adoption" + label = "Child or young person placed with the family (foster or adoption)" documentation = ( "A child or young person (the Child Benefit definition) who is not " "the claimant or partner and is placed with their benefit unit by a " @@ -14,10 +14,14 @@ class is_child_or_young_person_placed_with_family(Variable): "Jobseeker's Allowance, income-related Employment and Support " "Allowance and Housing Benefit they are not a member of the " "claimant's household, and under Housing Benefit they do not occupy " - "the claimant's dwelling. HB reg 21(3)(a) refers to a placement " - "under section 22C(2) of the Children Act 1989; the model follows " - "DWP's guidance that foster children are within reg 21(3) (LHA " - "Guidance Manual para 2.033)." + "the claimant's dwelling. Since SI 2017/901, HB reg 21(3)(a) refers " + "to a placement under section 22C(2) of the Children Act 1989, " + "which is placement with a parent; foster placements are under " + "s.22C(5)-(6), and the earlier text referred to s.23(2)(a). The " + "model treats foster placements as within reg 21(3), as the " + "'qualifying parent or carer' definition presupposes and as the " + "English pensioner and Welsh council tax reduction rules say " + "expressly ('section 22C'; 'section 22C or 23(2)(a)')." ) definition_period = YEAR reference = ( @@ -26,6 +30,8 @@ class is_child_or_young_person_placed_with_family(Variable): "https://www.legislation.gov.uk/uksi/1987/1967/regulation/16", "https://www.legislation.gov.uk/uksi/1996/207/regulation/78", "https://www.legislation.gov.uk/uksi/2008/794/regulation/156", + "https://www.legislation.gov.uk/uksi/2012/2885/regulation/8", + "https://www.legislation.gov.uk/wsi/2013/3029/regulation/8", "https://assets.publishing.service.gov.uk/media/5a758238ed915d6faf2b38a2/lha-guidance-manual.pdf", ) diff --git a/policyengine_uk/variables/gov/dwp/is_lha_foster_child.py b/policyengine_uk/variables/gov/dwp/is_lha_foster_child.py new file mode 100644 index 000000000..374f381ac --- /dev/null +++ b/policyengine_uk/variables/gov/dwp/is_lha_foster_child.py @@ -0,0 +1,36 @@ +from policyengine_uk.model_api import * + + +class is_lha_foster_child(Variable): + value_type = bool + entity = Person + label = "Foster child in the Universal Credit size criteria" + documentation = ( + "A person under 18 looked after by a local authority and placed with " + "the claimant or partner of their benefit unit. The renter is their " + "foster parent (UC Regs 2013 reg 2, a person with whom a child is " + "placed under the care planning regulations, where a child is a " + 'person under 18). The model reads "foster child" in Sch 4 para ' + '9(3) and "a child" in para 12(A1)(c) the same way, so a foster ' + "child aged 16 or 17 is not a non-dependant and has no bedroom of " + "their own, and their overnight care counts for the renter. The " + "narrower reading, under 16 as in the Welfare Reform Act 2012 s.40, " + "would instead make such a person a non-dependant with a bedroom " + "and give the renter no foster room. The guidance does not settle " + "which applies." + ) + definition_period = YEAR + reference = ( + "https://www.legislation.gov.uk/uksi/2013/376/regulation/2", + "https://www.legislation.gov.uk/uksi/2013/376/schedule/4/paragraph/9", + "https://www.legislation.gov.uk/uksi/2013/376/schedule/4/paragraph/12", + "https://www.legislation.gov.uk/ukpga/1989/41/section/105", + ) + + def formula(person, period, parameters): + age_limit = parameters(period).gov.dwp.LHA.foster_child_age_limit + return ( + person("is_looked_after_by_local_authority", period) + & (person("age", period) < age_limit) + & ~person("is_claimant_or_partner", period) + ) diff --git a/policyengine_uk/variables/gov/dwp/is_non_dependant_of_household_head.py b/policyengine_uk/variables/gov/dwp/is_non_dependant_of_household_head.py index 5042743e1..c5228ab41 100644 --- a/policyengine_uk/variables/gov/dwp/is_non_dependant_of_household_head.py +++ b/policyengine_uk/variables/gov/dwp/is_non_dependant_of_household_head.py @@ -15,10 +15,12 @@ class is_non_dependant_of_household_head(Variable): "Credit counts a non-dependant in one claim only, which the model " "gives to the household head's family; Housing Benefit and Council " "Tax Reduction apportion a non-dependant of several joint occupiers " - "between them. A non-dependant's own children are non-dependants " - "too; a child looked after by a local authority is not (see " - "LHA_allowed_bedrooms). Carers engaged through a charity are not " - "identified." + "between them. The flag covers every member of such a family, " + "including children. A non-dependant's own children are " + "non-dependants too, but a child or qualifying young person looked " + "after by a local authority is not (UC Sch 4 para 9(2)(g)); the " + "size criteria apply that exclusion (see LHA_allowed_bedrooms). " + "Carers engaged through a charity are not identified." ) definition_period = YEAR reference = ( diff --git a/policyengine_uk/variables/gov/dwp/lha_renter_meets_foster_parent_condition.py b/policyengine_uk/variables/gov/dwp/lha_renter_meets_foster_parent_condition.py index f4f26f299..fab56739b 100644 --- a/policyengine_uk/variables/gov/dwp/lha_renter_meets_foster_parent_condition.py +++ b/policyengine_uk/variables/gov/dwp/lha_renter_meets_foster_parent_condition.py @@ -26,15 +26,19 @@ class lha_renter_meets_foster_parent_condition(Variable): def formula(benunit, period, parameters): person = benunit.members claimant_or_partner = person("is_claimant_or_partner", period) - # UC Regs 2013 reg 2, "foster parent": a person with whom a child is - # placed under the care planning regulations; a child here is a - # person under 18 looked after by a local authority. - placed = ( - person("is_looked_after_by_local_authority", period) - | person("is_placed_for_adoption", period) - ) & (person("age", period) < 18) + # UC Regs 2013 reg 2, "foster parent": a person with whom a child + # (under 18) is placed under the care planning regulations; reg 89(3) + # and Sch 4 para 12(4)(b): an adopter with whom a child is placed for + # adoption. + age_limit = parameters(period).gov.dwp.LHA.foster_child_age_limit + placed_for_adoption = ( + person("is_placed_for_adoption", period) + & (person("age", period) < age_limit) + & ~claimant_or_partner + ) + placed = person("is_lha_foster_child", period) | placed_for_adoption # UC Regs 2013 Sch 4 para 12(4)(a)-(b) and (5). between_placements = claimant_or_partner & person( "is_approved_foster_parent_without_placement", period ) - return benunit.any((placed & ~claimant_or_partner) | between_placements) + return benunit.any(placed | between_placements) diff --git a/policyengine_uk/variables/gov/dwp/meets_lha_overnight_care_condition.py b/policyengine_uk/variables/gov/dwp/meets_lha_overnight_care_condition.py index ad86b14b6..f9da22caf 100644 --- a/policyengine_uk/variables/gov/dwp/meets_lha_overnight_care_condition.py +++ b/policyengine_uk/variables/gov/dwp/meets_lha_overnight_care_condition.py @@ -13,7 +13,12 @@ class meets_lha_overnight_care_condition(Variable): "Independence Payment) and has non-resident carers who regularly " "stay overnight to care for them. This is the Universal Credit " "overnight care condition and the Housing Benefit 'person who " - "requires overnight care'. Two Housing Benefit routes are not " + "requires overnight care'. The law also lists the Scottish child " + "disability payment, adult disability payment, Scottish adult " + "disability living allowance and pension age disability payment; " + "the model has no variables for those, so they count only where the " + "data records them as the DWP equivalents. Two Housing Benefit " + "routes are not " "modelled: a person without a qualifying benefit whose need the " "local authority accepts on other evidence, and the requirement that " "the carers have the use of a bedroom additional to the occupiers'." diff --git a/policyengine_uk/variables/gov/dwp/youngest_child_age_for_legacy_benefits.py b/policyengine_uk/variables/gov/dwp/youngest_child_age_for_legacy_benefits.py index de2c1449f..179e7d564 100644 --- a/policyengine_uk/variables/gov/dwp/youngest_child_age_for_legacy_benefits.py +++ b/policyengine_uk/variables/gov/dwp/youngest_child_age_for_legacy_benefits.py @@ -16,11 +16,16 @@ class youngest_child_age_for_legacy_benefits(Variable): "https://www.legislation.gov.uk/ukpga/1992/4/section/137", "https://www.legislation.gov.uk/ukpga/1992/4/section/142", "https://www.legislation.gov.uk/uksi/1987/1967/schedule/1B", + "https://www.legislation.gov.uk/uksi/1987/1967/regulation/16", ) def formula(benunit, period, parameters): person = benunit.members - child = person("is_child_for_child_benefit", period) & ~person( - "is_claimant_or_partner", period + # A child placed with the family by a local authority or for adoption + # is not a member of the household (IS Regs 1987 reg 16(4)). + child = ( + person("is_child_for_child_benefit", period) + & ~person("is_claimant_or_partner", period) + & ~person("is_child_or_young_person_placed_with_family", period) ) return benunit.min(where(child, person("age", period), np.inf)) diff --git a/policyengine_uk/variables/household/demographic/has_non_resident_overnight_carer.py b/policyengine_uk/variables/household/demographic/has_non_resident_overnight_carer.py index e60811980..4ce8137c6 100644 --- a/policyengine_uk/variables/household/demographic/has_non_resident_overnight_carer.py +++ b/policyengine_uk/variables/household/demographic/has_non_resident_overnight_carer.py @@ -9,9 +9,13 @@ class has_non_resident_overnight_carer(Variable): "Whether one or more people who do not live in the home are engaged, " "under arrangements made for that purpose, to provide this person " "with overnight care and to stay overnight in the home on a regular " - "basis. With a qualifying disability benefit, this gives the " - "household an additional bedroom in the Universal Credit and Housing " - "Benefit size criteria (see meets_lha_overnight_care_condition)." + "basis. With a qualifying disability benefit, this can give an " + "additional bedroom in the Universal Credit and Housing Benefit size " + "criteria (see meets_lha_overnight_care_condition): to the renter " + "whose extended benefit unit the person is in, or who fosters them " + "(UC), or to the claimant whose dwelling they occupy (HB). A " + "lodger's or joint tenant's carer gives the household head's family " + "nothing under Universal Credit." ) definition_period = YEAR default_value = False diff --git a/policyengine_uk/variables/household/demographic/is_looked_after_by_local_authority.py b/policyengine_uk/variables/household/demographic/is_looked_after_by_local_authority.py index 96b158ba7..93c3fef0b 100644 --- a/policyengine_uk/variables/household/demographic/is_looked_after_by_local_authority.py +++ b/policyengine_uk/variables/household/demographic/is_looked_after_by_local_authority.py @@ -16,7 +16,12 @@ class is_looked_after_by_local_authority(Variable): "criteria, and their carer meets the foster parent condition for an " "additional bedroom. Leave it false for a child placed for adoption " "(see is_placed_for_adoption) or placed with their own parent, for " - "whom Universal Credit treats the carer as responsible (reg 4A)." + "whom Universal Credit treats the carer as responsible (reg 4A). " + "Under Housing Benefit and the other legacy schemes, a child placed " + "with a parent by a local authority under Children Act 1989 s.22C(2) " + "is outside the household (HB Regs 2006 reg 21(3)(a)); one flag " + "cannot represent both, and the model treats such a child as a " + "household member." ) definition_period = YEAR default_value = False diff --git a/policyengine_uk/variables/household/demographic/is_placed_for_adoption.py b/policyengine_uk/variables/household/demographic/is_placed_for_adoption.py index eebe11ef2..56c659822 100644 --- a/policyengine_uk/variables/household/demographic/is_placed_for_adoption.py +++ b/policyengine_uk/variables/household/demographic/is_placed_for_adoption.py @@ -7,22 +7,30 @@ class is_placed_for_adoption(Variable): label = "placed for adoption" documentation = ( "Whether this child is placed for adoption with the claimant or " - "partner of their benefit unit (an adopter), or placed with them " - "prior to adoption. Put the child in the adopter's benefit unit and " - "leave is_looked_after_by_local_authority false: under Universal " - "Credit the adopter is responsible for the child (UC Regs 2013 reg " - "4A(1)(c)) and satisfies the foster parent condition for an " - "additional bedroom (Sch 4 para 12(4)(b)), and Pension Credit treats " - "them as the adopter's responsibility too (SPC Regs 2002 Sch IIA " - "para 4(3)(c)). Under Housing Benefit, the other legacy schemes and " - "council tax reduction the child is not a member of the claimant's " - "household (HB Regs 2006 reg 21(3)(b)-(c); CTR (England) prescribed " - "requirements reg 8(2)(b)-(c)), and no one is responsible for them " - "for Tax-Free Childcare (Childcare Payments (Eligibility) Regs 2015 " - "reg 4(2)(d)). Child Tax Credit excludes a child placed for adoption " - "only while the local authority pays for their accommodation or " - "maintenance (CTC Regs 2002 reg 3, rule 4 case B), which is not " - "modelled." + "partner of their benefit unit under the Adoption and Children Act " + "2002 or the Adoption and Children (Scotland) Act 2007. Put the child " + "in the adopter's benefit unit and leave " + "is_looked_after_by_local_authority false. A fostering-for-adoption " + "placement (Children Act 1989 s.22C(9A)-(9B)) is a foster placement: " + "flag that child as looked after instead. Universal Credit treats the " + "adopter as responsible for the child (UC Regs 2013 reg 4A(1)(c)), " + "and the adopter satisfies the foster parent condition for an " + "additional bedroom (Sch 4 para 12(4)(b)). That condition's " + "definition of adopter (reg 89(3)(a)) excludes a foster parent or " + "close relative of the child, which the model does not check. " + "Pension Credit also treats the adopter as responsible (SPC Regs 2002 " + "Sch IIA para 4(3)(c)). Under Housing Benefit, Income Support, " + "income-based Jobseeker's Allowance, income-related Employment and " + "Support Allowance and the English pensioner, Welsh and Scottish " + "pension-age council tax reduction schemes, the child is not a " + "member of the claimant's household. Tax-Free Childcare does not " + "count them (Childcare Payments (Eligibility) Regs 2015 reg " + "4(2)(d)). Child Tax Credit excludes them only while the local " + "authority pays for their keep (CTC Regs 2002 reg 3, rule 4 case B), " + "which is not modelled. Scottish working-age council tax reduction " + "excludes only foster placements (SSI 2021/249 reg 7(8)), so the " + "child should count there; the model's shared legacy household test " + "leaves them out." ) definition_period = YEAR default_value = False @@ -34,4 +42,5 @@ class is_placed_for_adoption(Variable): "https://www.legislation.gov.uk/uksi/2015/448/regulation/4", "https://www.legislation.gov.uk/uksi/2002/1792/schedule/IIA", "https://www.legislation.gov.uk/uksi/2002/2007/regulation/3", + "https://www.legislation.gov.uk/ssi/2021/249/regulation/7", ) From 500424e0e22e28bc55b7db0341a1fe2ccd67d81d Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 2 Oct 2026 04:44:47 -0400 Subject: [PATCH 6/8] Address review r2: looked-after only under 18, single couples, IS fostering - is_looked_after_child: the looked-after flag applies only under 18 (Children Act 1989 ss.22(1), 105(1)). It replaces the raw flag in the UC, CTC and Pension Credit child tests and in the legacy placement test, so a flagged 18- or 19-year-old qualifying young person keeps their UC room and gives no HB carer room. The looked-after age limit moves to household.demographic.looked_after_child_age_limit. - HB occupier couples need is_couple as well as two counted claimant or partner members, so relation_type SINGLE is respected again. - Income Support Sch 1B para 2: a single claimant or lone parent with whom a child is placed by a local authority is a prescribed category. - YAML: a looked-after 17-year-old claimant (pins the claimant-guard mutant), a looked-after 18-year-old with a single renter of 30, a non-dependant pair entered as single, two IS para 2 cases. - Property predicates apply the under-18 limit and accept any non-tertiary education; P5 renamed to a reference count. The child-definition property reference applies the same under-18 limit. - Documentation: HB reg 19(2)(c) eligible children; looked-after flag under 18 only. Co-Authored-By: Claude Opus 5.5 --- changelog.d/2011.fixed.md | 2 +- .../gov/dwp/LHA/foster_child_age_limit.yaml | 13 ---- .../looked_after_child_age_limit.yaml | 11 +++ ...lies_children_and_additional_bedrooms.yaml | 77 ++++++++++++++++++- .../family/LHA_young_person_bedroom.yaml | 4 +- .../benefit/family/income_support.yaml | 45 ++++++++++- ..._child_and_adult_definitions_properties.py | 10 ++- ...est_lha_bedroom_young_people_properties.py | 12 +-- .../housing_benefit_LHA_allowed_bedrooms.py | 4 +- .../gov/dwp/income_support_eligible.py | 17 +++- ...fying_young_person_for_child_tax_credit.py | 2 +- ...hild_or_young_person_placed_with_family.py | 10 ++- .../variables/gov/dwp/is_lha_foster_child.py | 7 +- ...ha_renter_meets_foster_parent_condition.py | 4 +- ...lifying_young_person_for_pension_credit.py | 2 +- ...fying_young_person_for_universal_credit.py | 5 +- .../is_looked_after_by_local_authority.py | 3 +- .../demographic/is_looked_after_child.py | 30 ++++++++ 18 files changed, 216 insertions(+), 42 deletions(-) delete mode 100644 policyengine_uk/parameters/gov/dwp/LHA/foster_child_age_limit.yaml create mode 100644 policyengine_uk/parameters/household/demographic/looked_after_child_age_limit.yaml create mode 100644 policyengine_uk/variables/household/demographic/is_looked_after_child.py diff --git a/changelog.d/2011.fixed.md b/changelog.d/2011.fixed.md index 9c8e9ebca..f77ad1bd6 100644 --- a/changelog.d/2011.fixed.md +++ b/changelog.d/2011.fixed.md @@ -1 +1 @@ -- Count the children of the household head's non-dependants (Universal Credit, UC Regs 2013 Sch 4 paras 9-10) and of non-dependants, boarders and lodgers (Housing Benefit, HB Regs 2006 reg 13D(12)) in the household head's LHA size criteria, sharing rooms with the head's own children. Give foster children no bedroom of their own, and foster parents, adopters with a child placed, and households with a non-resident overnight carer an additional bedroom (UC Sch 4 para 12; HB reg 13D(3A)-(3B)), with new inputs `is_placed_for_adoption`, `is_approved_foster_parent_without_placement` and `has_non_resident_overnight_carer`. Except foster parents from the shared accommodation rate (UC para 29(9A); HB "young individual"), and count armed forces independence payment in the UC para 29(5) exception. Give an occupier couple from another family one Housing Benefit bedroom (HB reg 13D(3)(a)). A child placed for adoption leaves the legacy household (HB reg 21(3), IS reg 16(4), JSA reg 78(4), ESA reg 156(5)) and is not a Tax-Free Childcare qualifying child (Childcare Payments (Eligibility) Regs 2015 reg 4(2)(d)). Treat a person under 18 looked after by a local authority and placed with the renter as the renter's foster child throughout the Universal Credit size criteria (`is_lha_foster_child`). Apply the 2017 extension of the overnight care bedroom beyond the renter or claimant from April 2017. Leave a child placed with the family out of the Income Support youngest-child test (IS reg 16(4)). +- Count the children of the household head's non-dependants (Universal Credit, UC Regs 2013 Sch 4 paras 9-10) and of non-dependants, boarders and lodgers (Housing Benefit, HB Regs 2006 reg 13D(12)) in the household head's LHA size criteria, sharing rooms with the head's own children. Give foster children no bedroom of their own, and foster parents, adopters with a child placed, and households with a non-resident overnight carer an additional bedroom (UC Sch 4 para 12; HB reg 13D(3A)-(3B)), with new inputs `is_placed_for_adoption`, `is_approved_foster_parent_without_placement` and `has_non_resident_overnight_carer`. Except foster parents from the shared accommodation rate (UC para 29(9A); HB "young individual"), and count armed forces independence payment in the UC para 29(5) exception. Give an occupier couple from another family one Housing Benefit bedroom (HB reg 13D(3)(a)). A child placed for adoption leaves the legacy household (HB reg 21(3), IS reg 16(4), JSA reg 78(4), ESA reg 156(5)) and is not a Tax-Free Childcare qualifying child (Childcare Payments (Eligibility) Regs 2015 reg 4(2)(d)). Treat a person under 18 looked after by a local authority and placed with the renter as the renter's foster child throughout the Universal Credit size criteria (`is_lha_foster_child`). Apply the 2017 extension of the overnight care bedroom beyond the renter or claimant from April 2017. Leave a child placed with the family out of the Income Support youngest-child test (IS reg 16(4)). Treat the looked-after flag as applying only under 18 (`is_looked_after_child`) in the UC, CTC, Pension Credit and legacy placement tests. Add Income Support Sch 1B para 2 (a single claimant or lone parent with whom a child is placed by a local authority). diff --git a/policyengine_uk/parameters/gov/dwp/LHA/foster_child_age_limit.yaml b/policyengine_uk/parameters/gov/dwp/LHA/foster_child_age_limit.yaml deleted file mode 100644 index f7c5c478a..000000000 --- a/policyengine_uk/parameters/gov/dwp/LHA/foster_child_age_limit.yaml +++ /dev/null @@ -1,13 +0,0 @@ -description: Age below which a child looked after by a local authority and placed with a renter is a foster child, making the renter a foster parent, in the Universal Credit size criteria. -values: - 2013-04-29: 18 -metadata: - unit: year - label: LHA foster child age limit - reference: - - title: Universal Credit Regulations 2013 reg 2, "foster parent" (a child placed under the Care Planning, Placement and Case Review (England) Regulations 2010) - href: https://www.legislation.gov.uk/uksi/2013/376/regulation/2 - - title: Universal Credit Regulations 2013 Sch 4 para 9(3), "foster child" - href: https://www.legislation.gov.uk/uksi/2013/376/schedule/4/paragraph/9 - - title: Children Act 1989 s.105(1), "child" means a person under the age of eighteen - href: https://www.legislation.gov.uk/ukpga/1989/41/section/105 diff --git a/policyengine_uk/parameters/household/demographic/looked_after_child_age_limit.yaml b/policyengine_uk/parameters/household/demographic/looked_after_child_age_limit.yaml new file mode 100644 index 000000000..20223de34 --- /dev/null +++ b/policyengine_uk/parameters/household/demographic/looked_after_child_age_limit.yaml @@ -0,0 +1,11 @@ +description: Age below which a person can be a child looked after by a local authority, and so a foster child. +values: + 2010-01-01: 18 +metadata: + unit: year + label: looked-after child age limit + reference: + - title: Children Act 1989 s.22(1) (a child who is looked after by a local authority) and s.105(1) ("child" means a person under the age of eighteen) + href: https://www.legislation.gov.uk/ukpga/1989/41/section/105 + - title: Universal Credit Regulations 2013 reg 2, "foster parent" and "looked after by a local authority" + href: https://www.legislation.gov.uk/uksi/2013/376/regulation/2 diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_other_families_children_and_additional_bedrooms.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_other_families_children_and_additional_bedrooms.yaml index 4281a5322..9d722cc08 100644 --- a/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_other_families_children_and_additional_bedrooms.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_other_families_children_and_additional_bedrooms.yaml @@ -1068,13 +1068,15 @@ housing_benefit_LHA_additional_bedrooms: [0, 2] housing_benefit_LHA_allowed_bedrooms: [2, 3] -- name: A claimant who is looked after gives no foster room +- name: A looked-after claimant aged 17 gives no foster room period: 2026 input: people: claimant: - age: 19 + age: 17 is_household_head: true + is_claimant_or_partner: true + current_education: UPPER_SECONDARY is_looked_after_by_local_authority: true benunits: family: @@ -1087,9 +1089,78 @@ brma: MAIDSTONE output: # The foster parent condition needs a child placed with the renter, not - # the renter's own status (UC reg 2; HB reg 2(1)). + # the renter's own status (UC reg 2; HB reg 2(1), reg 21(3)). is_lha_foster_child: false lha_renter_meets_foster_parent_condition: false LHA_additional_bedrooms: 0 + is_child_or_young_person_placed_with_family: false is_housing_benefit_qualifying_parent_or_carer: false housing_benefit_LHA_additional_bedrooms: 0 + +- name: A person aged 18 cannot be looked after, so a single renter of 30 has a qualifying young person's bedroom + period: 2026 + input: + people: + renter: + age: 30 + is_household_head: true + is_parent: true + young_person: + age: 18 + current_education: UPPER_SECONDARY + is_looked_after_by_local_authority: true + benunits: + family: + members: [renter, young_person] + households: + home: + members: [renter, young_person] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + # Children Act 1989 ss.22(1) and 105(1): only a person under 18 is looked + # after. UC: the renter is responsible for the qualifying young person + # (reg 4(2)), who has a bedroom (para 10(1)(b)); not a specified renter + # (para 28(3)): 2, C. HB: a member of the household aged 16 or over + # (13D(3)(b)): 2, C. No foster or carer room. + is_looked_after_child: [false, false] + is_child_or_qualifying_young_person_for_universal_credit: [false, true] + is_lha_shared_accommodation_rate_specified_renter: false + LHA_additional_bedrooms: 0 + LHA_allowed_bedrooms: 2 + LHA_category: C + is_child_or_young_person_placed_with_family: [false, false] + housing_benefit_LHA_additional_bedrooms: 0 + housing_benefit_LHA_allowed_bedrooms: 2 + housing_benefit_LHA_category: C + +- name: A non-dependant parent and adult son entered as single count one Housing Benefit bedroom each + period: 2026 + input: + people: + renter: + age: 60 + is_household_head: true + parent: + age: 50 + son: + age: 22 + benunits: + renter_family: + members: [renter] + parent_family: + members: [parent, son] + relation_type: SINGLE + households: + home: + members: [renter, parent, son] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + # Not a couple, so each is "a person who is not a child" (HB reg + # 13D(3)(b)): 3. The parent family's own figure follows the model's + # inferred claimant and partner (the eldest two adults); it has no rent, + # so it is unused. + housing_benefit_LHA_allowed_bedrooms: [3, 1] diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_young_person_bedroom.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_young_person_bedroom.yaml index 315a51ead..34eafbb28 100644 --- a/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_young_person_bedroom.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_young_person_bedroom.yaml @@ -141,8 +141,8 @@ output: is_qualifying_young_person_for_universal_credit: [false, true] is_child_or_qualifying_young_person_for_universal_credit: [false, false] - # Not under para 10(1)(b), and not a non-dependant (para 9(2)(g)), so no - # bedroom of their own. The carer they are placed with is a foster parent + # Not under para 10(1)(b), and not a non-dependant (para 9(2)(c) and (g)), + # so no bedroom of their own. The carer they are placed with is a foster parent # (reg 2: a person with whom a child is placed under the care planning # regulations, which place children under 18), so has one additional # bedroom (para 12(4)(a), (9)(b)): 2 bedrooms, category C. The model reads diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/income_support.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/income_support.yaml index 091b8e904..6e2ac52cc 100644 --- a/policyengine_uk/tests/policy/baseline/finance/benefit/family/income_support.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/income_support.yaml @@ -23,4 +23,47 @@ child_tax_credit: 0 child_benefit: 1825 income_support_eligible: true - income_support: 0 \ No newline at end of file + income_support: 0 + +- name: A single foster carer is in an Income Support prescribed category + period: 2025 + input: + people: + carer: + age: 30 + income_support_reported: true + foster_child: + age: 3 + is_looked_after_by_local_authority: true + benunits: + family: + members: [carer, foster_child] + output: + # IS Regs 1987 Sch 1B para 2: a single claimant or lone parent with whom + # a child is placed by a local authority. The foster child is not a + # member of the household (reg 16(4)), so the carer is a single claimant. + is_single_person: true + income_support_eligible: true + +- name: A lone parent with an older child and a young foster child is in an Income Support prescribed category + period: 2025 + input: + people: + parent: + age: 30 + income_support_reported: true + child: + age: 10 + foster_child: + age: 2 + is_looked_after_by_local_authority: true + benunits: + family: + members: [parent, child, foster_child] + output: + # Sch 1B para 1 needs a child under 5 in the household, which the foster + # child is not (reg 16(4)); para 2 covers a lone parent with whom a child + # is placed. + youngest_child_age_for_legacy_benefits: 10 + income_support_eligible: true + diff --git a/policyengine_uk/tests/test_child_and_adult_definitions_properties.py b/policyengine_uk/tests/test_child_and_adult_definitions_properties.py index 2bb2f7413..255500c71 100644 --- a/policyengine_uk/tests/test_child_and_adult_definitions_properties.py +++ b/policyengine_uk/tests/test_child_and_adult_definitions_properties.py @@ -187,13 +187,19 @@ def qualifying_young_person(p, programme): return True +def looked_after_child(p): + # Only a person under 18 can be looked after by a local authority: + # https://www.legislation.gov.uk/ukpga/1989/41/section/105 + return p["is_looked_after_by_local_authority"] and p["age"] < 18 + + def child_or_young_person(p, programme): # Encoded responsibility filters, without their statutory exceptions: # https://www.legislation.gov.uk/uksi/2013/376/regulation/4 # https://www.legislation.gov.uk/uksi/2002/2007/regulation/3 # https://www.legislation.gov.uk/uksi/2002/1792/schedule/IIA eligible = statutory_child(p["age"]) or qualifying_young_person(p, programme) - if programme != "child_benefit" and p["is_looked_after_by_local_authority"]: + if programme != "child_benefit" and looked_after_child(p): return False return eligible @@ -252,7 +258,7 @@ def legacy_child_or_young_person(p, claimant): # https://www.legislation.gov.uk/uksi/2006/213/regulation/21 return ( not claimant - and not p["is_looked_after_by_local_authority"] + and not looked_after_child(p) and child_or_young_person(p, "child_benefit") ) diff --git a/policyengine_uk/tests/test_lha_bedroom_young_people_properties.py b/policyengine_uk/tests/test_lha_bedroom_young_people_properties.py index 65d3b70cc..e80ae2d80 100644 --- a/policyengine_uk/tests/test_lha_bedroom_young_people_properties.py +++ b/policyengine_uk/tests/test_lha_bedroom_young_people_properties.py @@ -265,8 +265,9 @@ def fosters(fam): def in_qualifying_education(p, age_limit_for_entry=19): - """Full-time non-advanced education, entered before 19.""" - return p["current_education"] == "UPPER_SECONDARY" and ( + """Full-time non-advanced education (any education short of tertiary), + entered before 19.""" + return p["current_education"] not in ("NOT_IN_EDUCATION", "TERTIARY") and ( p["age"] < age_limit_for_entry or p["age_started_or_accepted_current_education_or_training"] < age_limit_for_entry @@ -301,14 +302,15 @@ def child_benefit_qualifying_young_person(p): def flags(p): """The added person's status, from the inputs alone.""" - looked_after = p.get("is_looked_after_by_local_authority", False) + # Only a person under 18 can be looked after (Children Act 1989 s.105). + looked_after = p.get("is_looked_after_by_local_authority", False) and p["age"] < 18 return dict( # A qualifying young person no one is responsible for (UC para # 9(2)(g); reg 4(6)(a)). unclaimed=looked_after and uc_qualifying_young_person(p), # The family's foster child: looked after and under 18 (UC reg 2, # "foster parent"; para 9(3)). - fostered=looked_after and p["age"] < 18, + fostered=looked_after, # Placed with the family by a local authority (HB reg 21(3)). placed=looked_after and child_benefit_qualifying_young_person(p), overnight=p.get("has_non_resident_overnight_carer", False), @@ -390,7 +392,7 @@ def test_a_foster_child_adds_only_the_foster_parents_bedroom(case): @PROPERTY_SETTINGS @given(scenario()) -def test_bedrooms_match_an_independent_count_of_the_size_criteria(case): +def test_bedrooms_match_a_reference_count_of_the_size_criteria(case): population, target, person = case situation, keys = build(population, (target, person)) sim, uc, hb = bedrooms(situation) diff --git a/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_allowed_bedrooms.py b/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_allowed_bedrooms.py index e11f0cec7..bbf65f77c 100644 --- a/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_allowed_bedrooms.py +++ b/policyengine_uk/variables/gov/dwp/housing_benefit_LHA_allowed_bedrooms.py @@ -67,7 +67,9 @@ def formula(benunit, period, parameters): # and only where both members are counted, so the halves always pair. counted = other_occupier & aged_16_or_over claimant_or_partner = counted & person("is_claimant_or_partner", period) - couple = person.benunit.sum(claimant_or_partner) == 2 + couple = (person.benunit.sum(claimant_or_partner) == 2) & person.benunit( + "is_couple", period + ) occupier_rooms = counted * where(claimant_or_partner & couple, 0.5, 1) is_head_family = benunit.any(person("is_household_head", period)) other_occupiers = is_head_family * benunit.max( diff --git a/policyengine_uk/variables/gov/dwp/income_support_eligible.py b/policyengine_uk/variables/gov/dwp/income_support_eligible.py index c0f6715ff..d504a3b22 100644 --- a/policyengine_uk/variables/gov/dwp/income_support_eligible.py +++ b/policyengine_uk/variables/gov/dwp/income_support_eligible.py @@ -6,7 +6,10 @@ class income_support_eligible(Variable): entity = BenUnit label = "Whether eligible for Income Support" definition_period = YEAR - reference = "https://www.legislation.gov.uk/uksi/1987/1967/schedule/1B" + reference = ( + "https://www.legislation.gov.uk/uksi/1987/1967/schedule/1B", + "https://www.legislation.gov.uk/uksi/1987/1967/schedule/1B/paragraph/2", + ) def formula(benunit, period, parameters): IS = parameters(period).gov.dwp.income_support @@ -18,6 +21,16 @@ def formula(benunit, period, parameters): ) lone_parent = benunit("is_lone_parent", period) lone_parent_with_young_child = lone_parent & youngest_child_5_or_under + # Schedule 1B para 2: a single claimant or lone parent with whom a + # child is placed by a local authority, such as a foster child. + person = benunit.members + foster_child = person("is_looked_after_child", period) & person( + "is_child_for_child_benefit", period + ) + single_or_lone_parent = benunit("is_single_person", period) | lone_parent + fosters_child = single_or_lone_parent & benunit.any( + foster_child & ~person("is_claimant_or_partner", period) + ) has_carers = add(benunit, period, ["is_carer_for_benefits"]) > 0 none_SP_age = ~benunit.any(benunit.members("is_SP_age", period)) has_esa_income = benunit("esa_income", period) > 0 @@ -25,7 +38,7 @@ def formula(benunit, period, parameters): capital = benunit("income_support_assessable_capital", period) limit = IS.means_test.capital.limit return ( - (has_carers | lone_parent_with_young_child) + (has_carers | lone_parent_with_young_child | fosters_child) & none_SP_age & ~has_esa_income & already_claiming diff --git a/policyengine_uk/variables/gov/dwp/is_child_or_qualifying_young_person_for_child_tax_credit.py b/policyengine_uk/variables/gov/dwp/is_child_or_qualifying_young_person_for_child_tax_credit.py index d765404b1..13a810d59 100644 --- a/policyengine_uk/variables/gov/dwp/is_child_or_qualifying_young_person_for_child_tax_credit.py +++ b/policyengine_uk/variables/gov/dwp/is_child_or_qualifying_young_person_for_child_tax_credit.py @@ -17,5 +17,5 @@ def formula(person, period, parameters): "is_child_for_child_tax_credit", period ) | person("is_qualifying_young_person_for_child_tax_credit", period) return child_or_qualifying_young_person & ~person( - "is_looked_after_by_local_authority", period + "is_looked_after_child", period ) diff --git a/policyengine_uk/variables/gov/dwp/is_child_or_young_person_placed_with_family.py b/policyengine_uk/variables/gov/dwp/is_child_or_young_person_placed_with_family.py index 8ab5cb8ce..4512a6905 100644 --- a/policyengine_uk/variables/gov/dwp/is_child_or_young_person_placed_with_family.py +++ b/policyengine_uk/variables/gov/dwp/is_child_or_young_person_placed_with_family.py @@ -21,7 +21,13 @@ class is_child_or_young_person_placed_with_family(Variable): "model treats foster placements as within reg 21(3), as the " "'qualifying parent or carer' definition presupposes and as the " "English pensioner and Welsh council tax reduction rules say " - "expressly ('section 22C'; 'section 22C or 23(2)(a)')." + "expressly ('section 22C'; 'section 22C or 23(2)(a)'). HB reg " + "19(2)(c) excludes from 'young person' anyone to whom the Children " + "(Leaving Care) Act 2000 s.6 applies, such as an eligible child aged " + "16 or 17 who has been looked after for 13 weeks since age 14; such " + "a person is an occupier, not placed. The model has no input for " + "that and treats every looked-after qualifying young person as " + "placed." ) definition_period = YEAR reference = ( @@ -38,7 +44,7 @@ class is_child_or_young_person_placed_with_family(Variable): def formula(person, period, parameters): # HB Regs 2006 reg 21(3)(a)-(c); IS Regs 1987 reg 16(4); JSA Regs # 1996 reg 78(4); ESA Regs 2008 reg 156(5). - placed = person("is_looked_after_by_local_authority", period) | person( + placed = person("is_looked_after_child", period) | person( "is_placed_for_adoption", period ) return ( diff --git a/policyengine_uk/variables/gov/dwp/is_lha_foster_child.py b/policyengine_uk/variables/gov/dwp/is_lha_foster_child.py index 374f381ac..aeb6da3f1 100644 --- a/policyengine_uk/variables/gov/dwp/is_lha_foster_child.py +++ b/policyengine_uk/variables/gov/dwp/is_lha_foster_child.py @@ -28,9 +28,6 @@ class is_lha_foster_child(Variable): ) def formula(person, period, parameters): - age_limit = parameters(period).gov.dwp.LHA.foster_child_age_limit - return ( - person("is_looked_after_by_local_authority", period) - & (person("age", period) < age_limit) - & ~person("is_claimant_or_partner", period) + return person("is_looked_after_child", period) & ~person( + "is_claimant_or_partner", period ) diff --git a/policyengine_uk/variables/gov/dwp/lha_renter_meets_foster_parent_condition.py b/policyengine_uk/variables/gov/dwp/lha_renter_meets_foster_parent_condition.py index fab56739b..7c4b1e31e 100644 --- a/policyengine_uk/variables/gov/dwp/lha_renter_meets_foster_parent_condition.py +++ b/policyengine_uk/variables/gov/dwp/lha_renter_meets_foster_parent_condition.py @@ -30,7 +30,9 @@ def formula(benunit, period, parameters): # (under 18) is placed under the care planning regulations; reg 89(3) # and Sch 4 para 12(4)(b): an adopter with whom a child is placed for # adoption. - age_limit = parameters(period).gov.dwp.LHA.foster_child_age_limit + age_limit = parameters( + period + ).household.demographic.looked_after_child_age_limit placed_for_adoption = ( person("is_placed_for_adoption", period) & (person("age", period) < age_limit) diff --git a/policyengine_uk/variables/gov/dwp/pension_credit/guarantee_credit/minimum_guarantee/additional/is_child_or_qualifying_young_person_for_pension_credit.py b/policyengine_uk/variables/gov/dwp/pension_credit/guarantee_credit/minimum_guarantee/additional/is_child_or_qualifying_young_person_for_pension_credit.py index fed598585..4a03ef495 100644 --- a/policyengine_uk/variables/gov/dwp/pension_credit/guarantee_credit/minimum_guarantee/additional/is_child_or_qualifying_young_person_for_pension_credit.py +++ b/policyengine_uk/variables/gov/dwp/pension_credit/guarantee_credit/minimum_guarantee/additional/is_child_or_qualifying_young_person_for_pension_credit.py @@ -13,5 +13,5 @@ def formula(person, period, parameters): "is_child_for_pension_credit", period ) | person("is_qualifying_young_person_for_pension_credit", period) return child_or_qualifying_young_person & ~person( - "is_looked_after_by_local_authority", period + "is_looked_after_child", period ) diff --git a/policyengine_uk/variables/gov/dwp/universal_credit/child_element/is_child_or_qualifying_young_person_for_universal_credit.py b/policyengine_uk/variables/gov/dwp/universal_credit/child_element/is_child_or_qualifying_young_person_for_universal_credit.py index b75cb06d2..6e89ee6f7 100644 --- a/policyengine_uk/variables/gov/dwp/universal_credit/child_element/is_child_or_qualifying_young_person_for_universal_credit.py +++ b/policyengine_uk/variables/gov/dwp/universal_credit/child_element/is_child_or_qualifying_young_person_for_universal_credit.py @@ -15,6 +15,9 @@ def formula(person, period, parameters): child_or_qualifying_young_person = person( "is_child_for_universal_credit", period ) | person("is_qualifying_young_person_for_universal_credit", period) + # UC Regs 2013 reg 4(6)(a): no one is responsible for a child or + # qualifying young person looked after by a local authority, which + # only a person under 18 can be. return child_or_qualifying_young_person & ~person( - "is_looked_after_by_local_authority", period + "is_looked_after_child", period ) diff --git a/policyengine_uk/variables/household/demographic/is_looked_after_by_local_authority.py b/policyengine_uk/variables/household/demographic/is_looked_after_by_local_authority.py index 93c3fef0b..f4a29dc9c 100644 --- a/policyengine_uk/variables/household/demographic/is_looked_after_by_local_authority.py +++ b/policyengine_uk/variables/household/demographic/is_looked_after_by_local_authority.py @@ -7,7 +7,8 @@ class is_looked_after_by_local_authority(Variable): label = "looked after by a local authority" documentation = ( "Whether this child or young person is looked after by a local " - "authority. A looked-after child who lives in the household, such as " + "authority. Only a person under 18 can be (see " + "is_looked_after_child), so the flag has no effect at 18 or over. A looked-after child who lives in the household, such as " "a foster child, is placed with the family whose benefit unit they " "are in: no one in it is responsible for them under Universal Credit " "(UC Regs 2013 reg 4(6)(a)), they are not a member of the claimant's " diff --git a/policyengine_uk/variables/household/demographic/is_looked_after_child.py b/policyengine_uk/variables/household/demographic/is_looked_after_child.py new file mode 100644 index 000000000..8cef42346 --- /dev/null +++ b/policyengine_uk/variables/household/demographic/is_looked_after_child.py @@ -0,0 +1,30 @@ +from policyengine_uk.model_api import * + + +class is_looked_after_child(Variable): + value_type = bool + entity = Person + label = "Child looked after by a local authority" + documentation = ( + "Whether this person is flagged is_looked_after_by_local_authority " + "and is under 18. Only a child, a person under 18, can be looked " + "after by a local authority (Children Act 1989 ss.22(1) and 105(1); " + "the Scottish and Welsh definitions are also limited to children), " + "so the flag has no effect at 18 or over: Universal Credit treats " + "the carer as responsible for a qualifying young person aged 18 or " + "19, and Housing Benefit counts them as a household member." + ) + definition_period = YEAR + reference = ( + "https://www.legislation.gov.uk/ukpga/1989/41/section/22", + "https://www.legislation.gov.uk/ukpga/1989/41/section/105", + "https://www.legislation.gov.uk/uksi/2013/376/regulation/2", + ) + + def formula(person, period, parameters): + age_limit = parameters( + period + ).household.demographic.looked_after_child_age_limit + return person("is_looked_after_by_local_authority", period) & ( + person("age", period) < age_limit + ) From e5c36dc45da69271c8e9105c44460477687b4806 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 2 Oct 2026 05:24:37 -0400 Subject: [PATCH 7/8] Address review r3: Income Support for adopters, explicit roles in the single case - Income Support Sch 1B para 2A: a single claimant or lone parent with whom a child is placed for adoption by an adoption agency is a prescribed category, so leaving the placed child out of the para 1 youngest-child test no longer removes eligibility. Two YAML cases. - The relation_type SINGLE YAML case now marks the parent and son's roles explicitly, so it asserts the legally correct [3, 2]; a separate case pins the is_couple guard on the renter's count. Co-Authored-By: Claude Opus 5.5 --- changelog.d/2011.fixed.md | 2 +- ...lies_children_and_additional_bedrooms.yaml | 45 +++++++++++++++++-- .../benefit/family/income_support.yaml | 41 +++++++++++++++++ .../gov/dwp/income_support_eligible.py | 13 +++--- 4 files changed, 91 insertions(+), 10 deletions(-) diff --git a/changelog.d/2011.fixed.md b/changelog.d/2011.fixed.md index f77ad1bd6..14da1ea11 100644 --- a/changelog.d/2011.fixed.md +++ b/changelog.d/2011.fixed.md @@ -1 +1 @@ -- Count the children of the household head's non-dependants (Universal Credit, UC Regs 2013 Sch 4 paras 9-10) and of non-dependants, boarders and lodgers (Housing Benefit, HB Regs 2006 reg 13D(12)) in the household head's LHA size criteria, sharing rooms with the head's own children. Give foster children no bedroom of their own, and foster parents, adopters with a child placed, and households with a non-resident overnight carer an additional bedroom (UC Sch 4 para 12; HB reg 13D(3A)-(3B)), with new inputs `is_placed_for_adoption`, `is_approved_foster_parent_without_placement` and `has_non_resident_overnight_carer`. Except foster parents from the shared accommodation rate (UC para 29(9A); HB "young individual"), and count armed forces independence payment in the UC para 29(5) exception. Give an occupier couple from another family one Housing Benefit bedroom (HB reg 13D(3)(a)). A child placed for adoption leaves the legacy household (HB reg 21(3), IS reg 16(4), JSA reg 78(4), ESA reg 156(5)) and is not a Tax-Free Childcare qualifying child (Childcare Payments (Eligibility) Regs 2015 reg 4(2)(d)). Treat a person under 18 looked after by a local authority and placed with the renter as the renter's foster child throughout the Universal Credit size criteria (`is_lha_foster_child`). Apply the 2017 extension of the overnight care bedroom beyond the renter or claimant from April 2017. Leave a child placed with the family out of the Income Support youngest-child test (IS reg 16(4)). Treat the looked-after flag as applying only under 18 (`is_looked_after_child`) in the UC, CTC, Pension Credit and legacy placement tests. Add Income Support Sch 1B para 2 (a single claimant or lone parent with whom a child is placed by a local authority). +- Count the children of the household head's non-dependants (Universal Credit, UC Regs 2013 Sch 4 paras 9-10) and of non-dependants, boarders and lodgers (Housing Benefit, HB Regs 2006 reg 13D(12)) in the household head's LHA size criteria, sharing rooms with the head's own children. Give foster children no bedroom of their own, and foster parents, adopters with a child placed, and households with a non-resident overnight carer an additional bedroom (UC Sch 4 para 12; HB reg 13D(3A)-(3B)), with new inputs `is_placed_for_adoption`, `is_approved_foster_parent_without_placement` and `has_non_resident_overnight_carer`. Except foster parents from the shared accommodation rate (UC para 29(9A); HB "young individual"), and count armed forces independence payment in the UC para 29(5) exception. Give an occupier couple from another family one Housing Benefit bedroom (HB reg 13D(3)(a)). A child placed for adoption leaves the legacy household (HB reg 21(3), IS reg 16(4), JSA reg 78(4), ESA reg 156(5)) and is not a Tax-Free Childcare qualifying child (Childcare Payments (Eligibility) Regs 2015 reg 4(2)(d)). Treat a person under 18 looked after by a local authority and placed with the renter as the renter's foster child throughout the Universal Credit size criteria (`is_lha_foster_child`). Apply the 2017 extension of the overnight care bedroom beyond the renter or claimant from April 2017. Leave a child placed with the family out of the Income Support youngest-child test (IS reg 16(4)). Treat the looked-after flag as applying only under 18 (`is_looked_after_child`) in the UC, CTC, Pension Credit and legacy placement tests. Add Income Support Sch 1B paras 2 and 2A (a single claimant or lone parent with whom a child is placed by a local authority, or placed for adoption). diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_other_families_children_and_additional_bedrooms.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_other_families_children_and_additional_bedrooms.yaml index 9d722cc08..3ad37a3c8 100644 --- a/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_other_families_children_and_additional_bedrooms.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_other_families_children_and_additional_bedrooms.yaml @@ -1135,17 +1135,20 @@ housing_benefit_LHA_allowed_bedrooms: 2 housing_benefit_LHA_category: C -- name: A non-dependant parent and adult son entered as single count one Housing Benefit bedroom each +- name: A non-dependant parent and adult son count one Housing Benefit bedroom each period: 2026 input: people: renter: age: 60 is_household_head: true + is_claimant_or_partner: true parent: age: 50 + is_claimant_or_partner: true son: age: 22 + is_claimant_or_partner: false benunits: renter_family: members: [renter] @@ -1160,7 +1163,41 @@ brma: MAIDSTONE output: # Not a couple, so each is "a person who is not a child" (HB reg - # 13D(3)(b)): 3. The parent family's own figure follows the model's - # inferred claimant and partner (the eldest two adults); it has no rent, - # so it is unused. + # 13D(3)(b)): the renter's 3. The parent's own size criteria: themself + # and the son, 2. + housing_benefit_LHA_allowed_bedrooms: [3, 2] + +- name: An explicit single relationship stops the Housing Benefit couple rule + period: 2026 + input: + people: + renter: + age: 60 + is_household_head: true + is_claimant_or_partner: true + adult_1: + age: 40 + is_claimant_or_partner: true + adult_2: + age: 38 + is_claimant_or_partner: true + benunits: + renter_family: + members: [renter] + other_family: + members: [adult_1, adult_2] + relation_type: SINGLE + households: + home: + members: [renter, adult_1, adult_2] + rent: 10_400 + tenure_type: RENT_PRIVATELY + brma: MAIDSTONE + output: + # With relation_type SINGLE the family is not a couple (is_couple), so + # reg 13D(3)(a) does not merge the two adults into one bedroom for the + # renter: 3. (The inputs flag both as claimant or partner, which a + # single family cannot have; only the renter's figure is the point, and + # the other family's 1 just reflects those inputs.) + is_couple: [false, false] housing_benefit_LHA_allowed_bedrooms: [3, 1] diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/income_support.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/income_support.yaml index 6e2ac52cc..ad09d44cd 100644 --- a/policyengine_uk/tests/policy/baseline/finance/benefit/family/income_support.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/income_support.yaml @@ -67,3 +67,44 @@ youngest_child_age_for_legacy_benefits: 10 income_support_eligible: true +- name: A single adopter with a child placed for adoption is in an Income Support prescribed category + period: 2025 + input: + people: + adopter: + age: 30 + income_support_reported: true + child: + age: 3 + is_placed_for_adoption: true + benunits: + family: + members: [adopter, child] + output: + # IS Regs 1987 Sch 1B para 2A. The child is not a member of the household + # (reg 16(4)(b)-(c)), so the adopter is a single claimant. + is_single_person: true + income_support_eligible: true + +- name: A lone parent with an older child and a young child placed for adoption is in an Income Support prescribed category + period: 2025 + input: + people: + parent: + age: 30 + income_support_reported: true + child: + age: 10 + placed_child: + age: 2 + is_placed_for_adoption: true + benunits: + family: + members: [parent, child, placed_child] + output: + # Para 1 needs a child under 5 in the household, which the placed child + # is not (reg 16(4)); para 2A covers a lone parent with whom a child is + # placed for adoption. + youngest_child_age_for_legacy_benefits: 10 + income_support_eligible: true + diff --git a/policyengine_uk/variables/gov/dwp/income_support_eligible.py b/policyengine_uk/variables/gov/dwp/income_support_eligible.py index d504a3b22..25342fbfb 100644 --- a/policyengine_uk/variables/gov/dwp/income_support_eligible.py +++ b/policyengine_uk/variables/gov/dwp/income_support_eligible.py @@ -9,6 +9,7 @@ class income_support_eligible(Variable): reference = ( "https://www.legislation.gov.uk/uksi/1987/1967/schedule/1B", "https://www.legislation.gov.uk/uksi/1987/1967/schedule/1B/paragraph/2", + "https://www.legislation.gov.uk/uksi/1987/1967/schedule/1B/paragraph/2A", ) def formula(benunit, period, parameters): @@ -22,14 +23,16 @@ def formula(benunit, period, parameters): lone_parent = benunit("is_lone_parent", period) lone_parent_with_young_child = lone_parent & youngest_child_5_or_under # Schedule 1B para 2: a single claimant or lone parent with whom a - # child is placed by a local authority, such as a foster child. + # child is placed by a local authority, such as a foster child; para + # 2A: or placed for adoption by an adoption agency. person = benunit.members - foster_child = person("is_looked_after_child", period) & person( - "is_child_for_child_benefit", period - ) + placed_child = ( + person("is_looked_after_child", period) + | person("is_placed_for_adoption", period) + ) & person("is_child_for_child_benefit", period) single_or_lone_parent = benunit("is_single_person", period) | lone_parent fosters_child = single_or_lone_parent & benunit.any( - foster_child & ~person("is_claimant_or_partner", period) + placed_child & ~person("is_claimant_or_partner", period) ) has_carers = add(benunit, period, ["is_carer_for_benefits"]) > 0 none_SP_age = ~benunit.any(benunit.members("is_SP_age", period)) From 1f3ce21a08e8341b25af524bc04d3c940ad844bd Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 2 Oct 2026 07:06:59 -0400 Subject: [PATCH 8/8] Address review r4 nits: ineligible IS cases, renter-only assertion, reuse placement test - Two Income Support cases that must be ineligible: a couple with a child placed for adoption, and a placement aged 16 (para 2A needs a single claimant or lone parent, and a child under 16). - The is_couple guard case asserts only the renter's bedrooms. - income_support_eligible reuses is_child_or_young_person_placed_with_family (under 16) instead of re-deriving it; renamed has_placed_child. - is_placed_for_adoption documentation mentions IS Sch 1B para 2A. Co-Authored-By: Claude Opus 5.5 --- ...lies_children_and_additional_bedrooms.yaml | 7 ++-- .../benefit/family/income_support.yaml | 37 +++++++++++++++++++ .../gov/dwp/income_support_eligible.py | 11 ++---- .../demographic/is_placed_for_adoption.py | 4 +- 4 files changed, 48 insertions(+), 11 deletions(-) diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_other_families_children_and_additional_bedrooms.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_other_families_children_and_additional_bedrooms.yaml index 3ad37a3c8..9b6d98243 100644 --- a/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_other_families_children_and_additional_bedrooms.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_other_families_children_and_additional_bedrooms.yaml @@ -1197,7 +1197,8 @@ # With relation_type SINGLE the family is not a couple (is_couple), so # reg 13D(3)(a) does not merge the two adults into one bedroom for the # renter: 3. (The inputs flag both as claimant or partner, which a - # single family cannot have; only the renter's figure is the point, and - # the other family's 1 just reflects those inputs.) + # single family cannot have, so only the renter's figure is asserted.) is_couple: [false, false] - housing_benefit_LHA_allowed_bedrooms: [3, 1] + benunits: + renter_family: + housing_benefit_LHA_allowed_bedrooms: 3 diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/income_support.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/income_support.yaml index ad09d44cd..60d02430e 100644 --- a/policyengine_uk/tests/policy/baseline/finance/benefit/family/income_support.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/income_support.yaml @@ -108,3 +108,40 @@ youngest_child_age_for_legacy_benefits: 10 income_support_eligible: true +- name: A couple with a child placed for adoption is not in the Income Support adoption category + period: 2025 + input: + people: + adopter_1: + age: 30 + income_support_reported: true + adopter_2: + age: 31 + child: + age: 2 + is_placed_for_adoption: true + benunits: + family: + members: [adopter_1, adopter_2, child] + output: + # Sch 1B para 2A covers only a single claimant or lone parent. + income_support_eligible: false + +- name: A placement aged 16 is not a child for the Income Support adoption category + period: 2025 + input: + people: + adopter: + age: 40 + income_support_reported: true + young_person: + age: 16 + current_education: UPPER_SECONDARY + is_placed_for_adoption: true + benunits: + family: + members: [adopter, young_person] + output: + # Para 2A needs "a child", a person under 16 (SSCBA 1992 s.137(1)). + income_support_eligible: false + diff --git a/policyengine_uk/variables/gov/dwp/income_support_eligible.py b/policyengine_uk/variables/gov/dwp/income_support_eligible.py index 25342fbfb..8e4c24728 100644 --- a/policyengine_uk/variables/gov/dwp/income_support_eligible.py +++ b/policyengine_uk/variables/gov/dwp/income_support_eligible.py @@ -26,14 +26,11 @@ def formula(benunit, period, parameters): # child is placed by a local authority, such as a foster child; para # 2A: or placed for adoption by an adoption agency. person = benunit.members - placed_child = ( - person("is_looked_after_child", period) - | person("is_placed_for_adoption", period) + placed_child = person( + "is_child_or_young_person_placed_with_family", period ) & person("is_child_for_child_benefit", period) single_or_lone_parent = benunit("is_single_person", period) | lone_parent - fosters_child = single_or_lone_parent & benunit.any( - placed_child & ~person("is_claimant_or_partner", period) - ) + has_placed_child = single_or_lone_parent & benunit.any(placed_child) has_carers = add(benunit, period, ["is_carer_for_benefits"]) > 0 none_SP_age = ~benunit.any(benunit.members("is_SP_age", period)) has_esa_income = benunit("esa_income", period) > 0 @@ -41,7 +38,7 @@ def formula(benunit, period, parameters): capital = benunit("income_support_assessable_capital", period) limit = IS.means_test.capital.limit return ( - (has_carers | lone_parent_with_young_child | fosters_child) + (has_carers | lone_parent_with_young_child | has_placed_child) & none_SP_age & ~has_esa_income & already_claiming diff --git a/policyengine_uk/variables/household/demographic/is_placed_for_adoption.py b/policyengine_uk/variables/household/demographic/is_placed_for_adoption.py index 56c659822..cf236868a 100644 --- a/policyengine_uk/variables/household/demographic/is_placed_for_adoption.py +++ b/policyengine_uk/variables/household/demographic/is_placed_for_adoption.py @@ -23,7 +23,9 @@ class is_placed_for_adoption(Variable): "income-based Jobseeker's Allowance, income-related Employment and " "Support Allowance and the English pensioner, Welsh and Scottish " "pension-age council tax reduction schemes, the child is not a " - "member of the claimant's household. Tax-Free Childcare does not " + "member of the claimant's household; a single claimant or lone " + "parent with such a child is in an Income Support prescribed " + "category (IS Regs 1987 Sch 1B para 2A). Tax-Free Childcare does not " "count them (Childcare Payments (Eligibility) Regs 2015 reg " "4(2)(d)). Child Tax Credit excludes them only while the local " "authority pays for their keep (CTC Regs 2002 reg 3, rule 4 case B), "