Skip to content

Replace generic child and adult flags with each programme's legal definitions - #1896

Open
MaxGhenis wants to merge 22 commits into
mainfrom
remove-is-child-flags
Open

MaxGhenis wants to merge 22 commits into
mainfrom
remove-is-child-flags

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Sep 29, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

UK law has no single definition of a child or an adult. Child Benefit, Universal Credit, tax credits, Pension Credit, the legacy means-tested benefits, the childcare schemes and student support each define their own, and statistics follow the Households Below Average Income (HBAI) definitions. The model used two generic flags instead, is_child (age < 18) and is_adult (age >= 18), plus about twenty variables built on them (num_children, num_adults, family_type, relation_type, is_married, child_index, the eldest/youngest ages, ...). This PR stops the model from reading any of them. Every use now reads the programme's own legal definition, an explicit age predicate where the rule really is age-only, or a variable named for its HBAI definition.

The age-18 split was also wrong in ways that changed results. The clearest case: a lone parent living with an 18-year-old still at school counted as a married couple on every measure (two people aged 18+), so the parent got the couple Pension Credit rate, WTC couple element and couple HB/CTR allowances, and £1,260 of Marriage Allowance transferred from their child. A 17-year-old living alone counted as a "couple" and a "lone parent" at once, with themselves as the child.

Design

Naming rule (from Max): programme rules use the programme's legal definition; anything defined the way HBAI defines it has hbai in its name.

HBAI (statistics only): is_hbai_dependent_child, is_hbai_adult, is_hbai_working_age_adult, is_hbai_pensioner, hbai_person_type (dependent child / working-age adult / pensioner, for poverty-by-group outputs), and the equivalence-scale child bands is_hbai_child_under_14 / is_hbai_child_aged_14_or_over. Source: HBAI background information and methodology FYE 2025, glossary. A dependent child is under 16, or 16-19, unpartnered, living with parents or a responsible adult, and in full-time non-advanced education or unwaged government training. Datasets should supply is_hbai_dependent_child directly (it is the FRS child-table record); the formula is a calculator fallback (see "Flagged assumptions").

Legal concepts shared across programmes: is_claimant_or_partner, the single adult or couple a benefit unit is formed around (SSCBA 1992 s.137(1) "family"; WRA 2012 ss.39-40; SPCA 2002 s.17; TCA 2002 s.3). Datasets can supply it. Otherwise the claimant is the benefit-unit head (or the eldest adult if the head is not an adult) and the partner at most one other HBAI adult (is_hbai_adult): a member flagged is_parent if there is one, else the eldest other adult who is not presumed the claimant's child. When the claimant is not flagged as a parent but two other members are, those two are the couple. A member under 20 and at least 16 years younger than the claimant is presumed to be their child (a PolicyEngine presumption for households entered without relationships, held as parameters and labelled as such). The HBAI dependency is visible, not hidden, and a benefit unit never has more than two claimants or partners. relation_type / is_couple / is_single now mean "the claimant has a partner" (the statutory "couple" is defined the same way across these Acts). is_lone_parent and is_single_person now follow IS Regs 1987 reg 2, HB Regs 2006 reg 2 and CTR (E) Regs 2012 reg 2, so lone parent, single person and couple are mutually exclusive; before, relation_type and family_type counted adults differently and HB/CTR could add a single and a couple allowance together. is_uc_claimant delegates to is_claimant_or_partner.

Programme definitions: existing child/QYP variables for Child Benefit, UC, CTC and Pension Credit; new is_responsible_for_child_or_qualifying_young_person_for_universal_credit, ..._for_child_tax_credit, is_child_or_young_person_for_legacy_benefits (IS, JSA(IB), ESA(IR), HB and CTR: under 16, or a Child Benefit qualifying young person) and is_responsible_for_child_or_young_person_for_legacy_benefits, is_child_for_working_tax_credit_childcare_element (SI 2002/2005 reg 14(3)-(4)), is_dependent_child_for_student_support (SI 2011/1986 reg 42), is_responsible_for_child_or_young_person_for_uc_or_housing_benefit (the benefit cap and LHA category serve both schemes: UC regs 4-5, HB reg 19), eldest_claimant_or_partner_age / youngest_claimant_or_partner_age.

Deprecated shims: is_child, is_adult, num_children, num_adults, benunit_count_children, benunit_count_adults, eldest_child_age, youngest_child_age, eldest_adult_age, youngest_adult_age, child_index, is_eldest_child, is_benunit_eldest_child, the six num_*disabled_{children,adults}, family_type, is_WA_adult, is_young_child, is_older_child. They keep their exact age-18 formulas and are labelled deprecated. They stay because downstream code still reads them: policyengine.py requests is_child/is_adult as default UK output columns; policyengine-uk-data uses them in calibration targets and imputation predictors; at least eight analysis repos with floating pins read them. Nothing inside policyengine-uk reads them any more, and tests/code_health/test_no_generic_child_adult_flags.py enforces that. Downstream migration: PolicyEngine/policyengine.py#537 (UK output columns, HBAI poverty groups, cliff denominator) and PolicyEngine/policyengine-uk-data#486 (supply is_hbai_dependent_child from the FRS; move calibration targets and imputation predictors onto the definitions of their own statistics).

Impact

Enhanced FRS 2024-25 (policyengine-uk-data 1.57.4, file sha256 03fe15e4...). This branch (f9814593) against main (44240bd8), both at policyengine-uk 2.102.6. Every aggregate computed is listed, with no omission threshold. Each changed benefit unit is assigned to the first matching mechanism, in the order listed below; every changed benefit unit matches one, and none is left unexplained. Scripts and saved outputs (with commit SHAs and the dataset hash) are listed at the end of this section.

Aggregates, £m (mechanisms from the 2026 decomposition)

Programme 2024 2026 2029 2026 by mechanism
Pension Credit -108.7 -109.4 -96.7 severe disability couple rule -112.7; claimant structure +3.3
Pension Credit recipients (thousands) -70.6 -68.4 -57.7
Universal Credit +12.9 +27.7 +249.8 LHA disability exception +52.5; household capital split +21.0; claimant structure -45.8
Targeted childcare (2-year-old offer) -39.2 -47.0 -45.2 phantom Guarantee Credit passport -43.1; claimant structure -2.9; severe disability rule -1.0
Marriage Allowance (allowance transferred) -28.0 -23.7 -23.2 claimant structure: no transfer from a child (19,800 fewer recipients in 2026)
Housing Benefit -17.6 -19.9 -23.0 severe disability rule (Guarantee Credit lost, so HB's capital passport goes) -10.0; phantom Guarantee Credit passport -7.9; claimant structure -2.1
Extended childcare +8.9 +16.0 +17.3 claimant structure: a 19-year-old at school no longer faces the parents' work and income test
Income tax +4.2 +3.4 +3.3 claimant structure: the Marriage Allowance change
Income Support -65.5 0.0 0.0 2024, claimant structure: almost all of it one survey record, a lone parent with an 18-year-old at school whom main treated as a couple
Council Tax Reduction, benefit cap reduction, Tax-Free Childcare, universal childcare, Child Benefit, Care to Learn, Childcare Grant, Parents' Learning Allowance, Adult Dependants' Grant, ESA(IR), JSA(IB), WTC, CTC 0.0 0.0 0.0
Government balance +243.4 +149.9 -88.3 household net income moves by the opposite amount

The government balance changes sign in 2029 because of the single-record UC change described below.

The mechanisms, in the order they are assigned (2026 counts):

  1. Claimant structure (34,500 benefit units; 189 records): who the claimant and partner are. A dependent 18- or 19-year-old is no longer a partner, so a lone parent is no longer a couple. A pensioner couple with a teenager at school claims Pension Credit as a couple with a qualifying young person, not Universal Credit (main also counted the teenager's own disability benefit towards the couple's severe disability addition). Members who are neither claimant, partner nor the programme's child or young person no longer count in the UC, HB, IS, tax credit and CTR means tests; in the FRS every such benefit unit already falls under this mechanism.
  2. Severe disability couple rule (79,700 benefit units; 98 records): SPC Regs Sch I para 1(1)(b)-(c). A couple where one partner receives Attendance Allowance, DLA care or PIP daily living and the other is not blind is not severely disabled; main paid the addition (£86.05 a week) per qualifying member. About 84,000 benefit units that receive Pension Credit on main lose the addition, and about 71,000 of them lose Pension Credit entirely. The FRS has no blindness variable, so head (c) (one partner qualifying, the other blind) never applies in the microsimulation.
  3. LHA disability exception (20,300; 18 records): UC Sch 4 para 29(5). Single renters under 35 receiving PIP daily living, AA or DLA care move from the shared accommodation rate to the one-bedroom rate.
  4. Household capital split (21,800; 22 records): unobserved household capital is shared among the household's claimants and partners, so a change of claimants anywhere in the household moves each benefit unit's share. Mostly this is a 16- or 17-year-old heading their own benefit unit now counting as a claimant. In a few households of young adults it is an 18- or 19-year-old who stopped being a claimant. The allocation is a PolicyEngine convention (flagged below).
  5. Phantom Guarantee Credit passport (9,700; 34 records): main computed Guarantee Credit for families not eligible for Pension Credit, which passported working-age families into the targeted childcare offer and mixed-age couples into Housing Benefit's capital disregard.

Single-record sensitivity. In 2029 Universal Credit rises £249.8m, and one survey record accounts for more than the whole rise: a lone-parent family whose share of the household's capital drops under the UC capital limit once that capital is split with a 16- or 17-year-old heading their own benefit unit in the same household. In 2026 the same split raises the family's UC only slightly.

Benefit-unit structure (weighted thousands, 2024 / 2026 / 2029): couples -486.3 / -491.6 / -497.6; lone parents -347.0 / -350.9 / -355.1; single persons +383.2 / +387.5 / +392.2. is_married is unchanged because the FRS supplies it.

Poverty, 2026, percentage points. "Aged under 18" is an age band; the HBAI groups use this branch's hbai_person_type applied to the same people in both runs (main has no such variable).

Measure All Aged under 18 HBAI dependent child HBAI working-age adult HBAI pensioner
Absolute BHC +0.019 +0.010 +0.012 +0.012 +0.051
Absolute AHC -0.072 -0.239 -0.180 -0.060 +0.020
Relative BHC +0.011 -0.006 -0.001 -0.003 +0.073
Relative AHC +0.011 -0.007 -0.003 -0.019 +0.135
  • The child absolute AHC fall (-0.24 points aged under 18, -0.18 points HBAI) is that same single survey record crossing the line. It is the same in 2024 and 2029.
  • 2024 relative AHC pensioner poverty rises 0.80 points (all people +0.11). That is one survey record: a pensioner couple losing the severe disability addition and falling below the 2024 line. In 2029 the pensioner change is +0.07 points.
  • 2029 absolute BHC falls 0.22 points for under-18s (0.17 for HBAI dependent children), again that single record (the capital split above).
  • Every other group and measure in 2024 and 2029 moves by less than 0.08 points.

HBAI-group rates on this branch (2026, relative AHC): dependent children 32.02%, working-age adults 22.05%, pensioners 17.10%.

Reproduction (review folder, not in the repo):

  • impact2.py runs a snapshot, recording the commit, dirty files, package versions and dataset hash.
  • compare2.py compares two snapshots record by record.
  • decomp_snapshot.py and decompose.py attribute each changed benefit unit to its first matching mechanism.
  • diag2.py produces record-level diagnostics, kept local and not published.
  • dynamics_parity.py checks the dynamics helper against the old shims on the full survey: 0 mismatches among 113,620 people in each of 2024, 2026 and 2029.

Earlier impact figures in this PR's history came from older heads and are superseded.

Audit: every use site

Each row: where the model read a generic flag (or a variable built on one), the legal definition that governs it, the citation (all fetched from legislation.gov.uk or gov.uk while doing this work), and whether results change. "Edge" means only unusual household structures move.

Benefit-unit structure (shared)

Use site Legal definition now used Citation Behaviour change
is_claimant_or_partner (new; replaces "is an adult" as the claimant/partner test) The claimant and, if any, one partner; never more than two. Datasets supply it or the benefit-unit head plus one partner is inferred (an identified parent, else the eldest other adult not presumed the head's child: under 20 and 16+ years younger) SSCBA s.137(1), WRA 2012 ss.39-40 Yes (calculator): an 18- or 19-year-old entered without relationships is the parent's child, not a third claimant; the age presumption is a PolicyEngine convention (flagged)
relation_type, is_couple, is_single (read by PC, WTC, TFC, HB, CTR, IS, premiums, DfE grants) Couple = the claimant has a partner (two claimants or partners in the benefit unit) SSCBA s.137(1), WRA 2012 s.39, SPCA 2002 s.17, TCA 2002 s.3 Yes: lone parent + 18/19-year-old dependant is single; a 16/17-year-old living alone is single
is_lone_parent, is_single_person No partner, and responsible / not responsible for a child or young person IS reg 2, HB reg 2, CTR (E) reg 2 Yes: now mutually exclusive with is_couple
is_married (fallback only; FRS supplies it) Couples presumed married (flagged) ITA 2007 s.55C Calculator only
marital_status (fallback only) Only the spouses are married, not their children ITA 2007 s.55C Calculator only
is_uc_claimant Claimant or partner (is_claimant_or_partner) WRA 2012 s.40, UC reg 3 Edge: an 18/19-year-old in non-advanced education who fails a UC QYP limb is a dependant, not a partner; without relationship inputs, an 18/19-year-old at least 16 years younger than the head is not a joint claimant (is_uc_claimant.yaml Case 6)
adult_index Explicit rank among household members aged 18 or over (modelling index; no law) n/a No
household_equivalisation_bhc/ahc HBAI modified OECD scale over HBAI adults and dependent children HBAI FYE 2025 Table 4 Only households with no one aged 18+ (lone 17-year-old: 1.00 to 0.67 BHC)

Universal Credit

Use site Legal definition now used Citation Behaviour change
is_uc_eligible (read is_WA_adult) Age basic conditions apply to claimants: 18+ (16+ in observable reg 8 cases) and below pension age; mixed-age couples kept WRA 2012 ss.3-4, UC regs 3, 8 Yes: a 17-year-old lone parent can claim; pensioners whose only working-age member is a dependant cannot
uc_childcare_work_condition Claimant and partner in paid work UC reg 32 Yes: a non-working 18-year-old dependant no longer blocks it
uc_assessable_capital, household_uc_unreported_adults (renamed household_uc_unreported_claimants) Capital of claimants and partners (allocation of unobserved household capital is a PE convention) WRA 2012 s.5, UC reg 18 Yes (allocation shares)
is_uc_work_allowance_eligible Responsible for a child or QYP (new shared variable) UC reg 22 No
uc_individual_child_element (local named child_index) Already uc_child_index; local renamed UC reg 24 No
benefit_cap (read num_adults, num_children) Single rate: no partner and not responsible for a child or young person. One cap serves UC (child/QYP, including every 16-year-old until the September after their birthday) and HB (child/young person as for Child Benefit), so the family rate applies if either test is met UC reg 80A, UC reg 5, HB reg 75CA, HB reg 19 Yes: a 16/17-year-old claiming alone gets the single cap
LHA_category (read is_child, is_adult) Shared accommodation rate: single renter under 35, no child or young person (UC or HB test), no non-dependant, and not an excepted person receiving AA, DLA care (middle/highest) or PIP daily living (para 29(5)) UC Sch 4 paras 27-29, HB reg 13D Yes (edge): non-disabled 16/17-year-olds living alone get the shared rate; disabled renters under 35 are excepted (they were not before, at any age 18+); co-resident 16/17-year-old claimants count as non-dependants

Pension Credit

Use site Legal definition now used Citation Behaviour change
is_pension_credit_eligible (read is_adult) Every claimant or partner at State Pension age SPCA 2002 ss.1, 4(1A) Yes: pensioners with an 18/19-year-old at school become eligible
standard_minimum_guarantee, savings_credit, is_savings_credit_eligible (read relation_type) Claimant with / without a partner SPCA s.2(5), SPC regs 6, 7 Yes: single rates for a pensioner living with an 18/19-year-old
severe_disability_minimum_guarantee_addition (read is_adult) Single claimant with a qualifying benefit and no carer benefit paid for them; a couple where both qualify (double amount with no carer benefit, single amount with one) or one qualifies and the other is blind; children and QYPs ignored SPC Sch I paras 1-2, SPC reg 6(5) Yes: a child no longer vetoes the addition; a dependant's benefit no longer adds one; a couple where only one partner qualifies and the other is not blind no longer gets it; a carer benefit for one of two qualifying partners now leaves the single amount instead of nil
carer_minimum_guarantee_addition Claimant or partner who is a carer SPC Sch I para 4 Yes (edge)
pension_credit_income, pension_credit_earnings, savings_credit_income Claimant's income includes the partner's, not the children's SPCA s.5, SPC reg 9 Yes
guarantee_credit Part of State Pension Credit: zero unless PC-eligible SPCA ss.1-2 Yes: working-age families no longer passported into targeted childcare, and mixed-age couples into HB, by a phantom Guarantee Credit
child_minimum_guarantee_addition (local named is_child) Already PC child/QYP; local renamed SPC Sch IIA No

Tax credits

Use site Legal definition now used Citation Behaviour change
WTC_lone_parent_element (read family_type) Single claim, responsible for a child or QYP (CTC rules) WTC reg 12, CTC reg 3 Yes
WTC_couple_element (read relation_type) Joint claim by a couple WTC reg 11 Yes
is_WTC_eligible (read family_type, num_disabled_adults, eldest/youngest adult age) Reg 4 routes on the claimant(s): lone parent 16 h, couple with children 24 h, 25+ at 30 h, disabled claimant WTC reg 4 Yes
WTC_disabled_element (read is_adult) Disabled claimant or joint claimant working 16 h WTC reg 9 Yes
WTC_severely_disabled_element (read num_severely_disabled_adults) Severely disabled claimant or joint claimant WTC reg 17 Yes
WTC_childcare_element (read num_children) Child until the September after their 15th birthday (16th if disabled) WTC reg 14(3)-(4) Yes

Legacy means-tested benefits (IS, JSA(IB), ESA(IR), HB, CTR)

Use site Legal definition now used Citation Behaviour change
is_child_or_young_person_for_legacy_benefits (new; read by is_lone_parent and the legacy child amounts) Child = under 16, young person = CB QYP; not the claimant or partner; not a child placed by a local authority SSCBA s.137, IS regs 14, 16(4), HB regs 19, 21(3) Yes (edge): a foster or looked-after child no longer makes the carer a lone parent
housing_benefit_eligible (pension-age route added on main by #1901, read is_adult) New claims only where the claimant and any partner have reached the qualifying age for State Pension Credit SI 2014/1230 reg 6A(4) Yes (edge): a pensioner living with an 18- or 19-year-old dependant can claim HB (and so not UC)
uc_earned_income, uc_unearned_income, housing_benefit_applicable_income, income_support_applicable_income, tax_credits_applicable_income, council_tax_reduction_applicable_income (summed every member) The claimant's and partner's income; the model also keeps counting the programme's own children and young persons, as before (flagged) UC reg 22, HB reg 25, IS reg 23, TCA s.7, CTR (E) Sch 1 para 11 Yes (edge): a member who is neither claimant, partner nor the programme's child or young person no longer counts
income_support_applicable_amount Personal allowances by the claimant's and partner's ages; child = under 16, young person = CB QYP IS Sch 2 para 1, IS reg 14 Yes (the under-18 rates were unreachable)
income_support_eligible Lone parent with a child under 5 IS Sch 1B para 1, SSCBA s.137 Edge
income_support_applicable_income, housing_benefit_applicable_income_disregard Lone parent / couple / single disregards, mutually exclusive IS Sch 8, HB Sch 4 Yes: no stacked disregards
housing_benefit_applicable_amount, council_tax_reduction_applicable_amount Claimant's and partner's ages HB Sch 3 para 1, CTR (W) Sch 7 Edge
housing_benefit_applicable_income_childcare_element Children until the September after their 15th birthday (16th if disabled) HB regs 27-28 Yes
council_tax_reduction_household_has_non_dep_exemption Applicant or partner, not a dependant CTR (E) Sch 1 para 8 Yes
IS, JSA, ESA, HB *_assessable_capital Capital of the claimant and partner; children's capital excluded (allocation is a PE convention) IS reg 23, JSA reg 88, ESA reg 83, HB reg 25 Yes (allocation shares)
disability_premium, enhanced_disability_premium, severe_disability_premium Claimant or partner meets the condition IS Sch 2 paras 11-14, HB Sch 3 paras 12-16 Yes: a disabled 18/19-year-old dependant no longer triggers the adult premium

HMRC and reforms

Use site Legal definition now used Citation Behaviour change
marriage_allowance, partners_unused_personal_allowance (read is_adult) Election between spouses or civil partners ITA 2007 ss.55B-55C Yes: no transfer from a child's unused allowance
tax_free_childcare_work_condition (read is_adult) The person applying and their partner, aged 16+ CPA 2014 ss.3, 6, SI 2015/448 regs 3, 9 Yes: a child's work no longer satisfies it; a non-working 17-year-old lone parent is not a "couple"
adult_index_cg (read is_adult) Explicit age-18 rank (modelling budget; CGT has no age condition) TCGA 1992 s.1 No
CPS marriage reforms (is_adult, marital_status, child-age test) Spouses only; child under the parameter age reform Reform only

DfE

Use site Legal definition now used Citation Behaviour change
care_to_learn_eligible (read is_child) The parent gets Child Benefit for the child (never themselves) ESFA conditions of grant (guidance), SSCBA s.142 Edge
childcare_grant_child_eligible (defined_for is_child) Dependent child of the student under 15 (17 with SEN) SI 2011/1986 regs 42, 45 No
parents_learning_allowance_dependent_children (read is_child) Dependent children, no age limit SI 2011/1986 regs 42, 46 Yes: an 18-year-old dependant at school counts
extended_childcare_entitlement_eligible (read is_child) Income test on the parent and partner only Childcare Act 2016 s.1, SI 2022/1134 regs 14-15 Yes
maintenance_loan_has_sponsor, maintenance_loan_sponsor_income (read is_adult) Redundant with the existing age >= 29 sponsor heuristic SI 2011/1986 Sch 4 No

Modelling code (no law governs these)

Use site Now Behaviour change
attends_private_school (read is_child) age_under_18 explicit age band No
private_school_vat (local num_children) Renamed num_private_school_pupils No
dynamics/participation.py, progression.py (read benunit_count_children, youngest_child_age, benunit_count_adults) Explicit age-18 composition helper (dynamics/demographics.py), identical for all 113,620 FRS people No

Flagged assumptions (kept at current behaviour or proxied, not silently)

  • HBAI dependent child, calculator fallback. Datasets should supply is_hbai_dependent_child from the FRS child table (Supply is_hbai_dependent_child from the FRS and move targets and imputations off the deprecated is_child/is_adult policyengine-uk-data#486). Without it:
    • a 16- or 17-year-old who is neither the benefit-unit head nor an identified parent is treated as a dependant whatever their education inputs (the FRS puts non-dependent 16-17-year-olds in their own benefit unit; this keeps the old age-18 treatment);
    • an 18- or 19-year-old in non-advanced education or approved training is a dependant only if the benefit unit has an identified parent (is_parent, aged 16+). Without one the model cannot tell a dependant from a partner and keeps treating them as an adult (for example a 24-year-old and a 19-year-old in sixth form stay a couple: claimant_relationships.yaml Case 7).
  • is_married fallback presumes couples are married; the FRS supplies the real value.
  • One benefit cap and one LHA category serve both UC and HB, so their family rates apply if either scheme's child or young-person test is met (UC regs 4-5, with every 16-year-old counted for the reg 5(1)(a) window; HB reg 19). A UC-only family whose 19-year-old is past UC's terminal date therefore keeps the family rate, as on main. Routing each scheme to its own test would expose the unmodelled Child Benefit leaver extension and underpay HB families. The LHA non-dependant proxy counts any other claimant or partner in the household and does not identify joint tenants, lodgers or landlords; of the UC Sch 4 para 29 exceptions only the disability benefits (para 29(5)) are observed.
  • is_claimant_or_partner presumes that a member under 20 and at least 16 years younger than the benefit-unit head is the head's child, not their partner, when relationships are not supplied (parameters household.demographic.benefit_unit.presumed_child). A 19-year-old partner of a 36-year-old entered without is_claimant_or_partner is therefore treated as their child; supply the flag to override.
  • Pension Credit severe disability addition: the person cared for is not observed, so each carer benefit paid in the benefit unit is taken to be for a different claimant or partner, never for its own recipient. The FRS has no blindness input, so head (c) applies only to calculator households.
  • UC, HB, IS, tax credit and CTR means tests still count the programme's own children's and young persons' income, as main did. The regulations count only the claimant's and partner's (UC reg 22, HB reg 25(3), IS reg 23(1), TCA s.7, CTR (England) Sch 1 para 11). Dropping it now would raise UC by about £4.8bn in 2026 (the saved trial run at 9b135036), because some survey records give children adult-level incomes, so it waits for a data fix. Members outside the programme's family no longer count, in either income or the hours behind the Housing Benefit worker disregard.
  • A benefit-unit member who is neither claimant, partner nor the programme's child or young person no longer counts in the means tests, but is not treated as a non-dependant either: non-dependant deductions look only at other benefit units. The FRS puts non-dependants in their own benefit units, so this arises only for households entered in the calculator.
  • Without relationship inputs, an adult of 20 or over who is not flagged as a parent can be the partner, so a lone parent entered with an adult child aged 20+ is treated as a couple, as on main.
  • UC reg 8 limbs (e)-(g) and the reg 8(2) care-leaver exclusion are not observable; limbs (a)-(d) use proxies (LCWRA for LCW; is_carer_for_benefits; a claimant with a UC child).
  • Capital allocation across benefit units (IS, JSA, ESA, HB, UC) remains a PolicyEngine convention; only the owner set (claimant and partner) is legal.
  • Not fixed here, now in follow-up tasks: the Pension Credit severe disability household non-dependant bar, reg 4A terminal dates, the SI 2019/37 art 4 saving and the Savings Credit 6 April 2016 date (a follow-up branch is already stacked on this one); the UC reg 5(1)(a) unconditional QYP route for 16-year-olds in the UC child element (the cap and LHA category already count it); IS Sch 1B "under 5" (the model keeps <= 5); WTC/HB childcare caps uprated instead of fixed at £175/£300; WTC disabled element once per couple; State Pension age rise to 67; employer NI above State Pension age; DfE scheme gaps (Care to Learn per child, extended childcare 9-month and partner routes, maintenance loan age-25 test, TFC disability list); cliff_evaluated for under-18s.

Invariants (property-based and differential tests)

policyengine_uk/tests/test_child_and_adult_definitions_properties.py (exhaustive over 6,656 combinations of age 0-25, every education status, head/parent/approved-training/own-benefit/looked-after flags, plus 1,728 boundary cases and four Hypothesis properties):

  1. Statute conformance. The CB, UC, CTC and PC child predicates are exactly "under 16"; their QYP predicates match the age/education/entry conditions the model encodes; the legacy child-or-young-person is the CB child/QYP minus the claimant, the partner and children placed by a local authority; the HBAI fallback and the claimant-or-partner presumption follow their documented rules; the WTC childcare child follows reg 14(3)-(4); the student-support dependent child is every non-claimant member.
  2. Partitions and bounds. hbai_person_type puts everyone in exactly one group. Any benefit unit (arbitrary ages, education, parent flags and head position) has at most two claimants/partners, all HBAI adults, and at least one exactly when it has an HBAI adult; a family of one or two adults (20+) plus dependants has exactly its adults. Couple/single, and couple/lone parent/single person, partition benefit units; a head aged 16+ is a claimant or partner unless two other members are flagged parents and the head is not.
  3. Differential. All 23 deprecated shims keep their age-18 formulas (including sentinels and tie-breaks), and wherever the rule stays age-only (attends_private_school, adult_index, adult_index_cg, the labour-supply groups) the explicit age_under_18 predicate agrees with the old flags for every input. The dynamics helper reproduces the old shim values for all 113,620 people in the enhanced FRS (1.57.4) in 2024, 2026 and 2029 (dynamics_parity.py, 0 mismatches, output saved).
  4. Monotonicity. Adding a child under 16 never changes who the claimant and partner are.
  5. Housing Benefit (test_housing_benefit_pension_age_properties.py, from Let pension-age families make new Housing Benefit claims #1901, now on the claimant and partner): 0 <= HB <= rent, within the LHA cap, never with UC, never to non-renters or above the capital limit; in calculator mode a family is eligible exactly when the claimant and any partner are over State Pension age, it rents and its capital is within the limit (dependants aged 18 or 19 do not count); in dataset mode HB goes only to reported claimants; would_claim_uc never changes a pension-age family's HB; HB is non-increasing in private pension income. This property found that a parent flag on an under-16 turned an older student into a dependant; an identified parent must now be 16+ (the minimised counterexample is a regression test).
  6. Means-test income (test_means_test_income_properties.py): giving income to a member who is neither claimant, partner nor any programme's child or young person never changes UC earned or unearned income, or HB, IS, tax credit, CTR or Pension Credit income.

Plus tests/code_health/test_no_generic_child_adult_flags.py: no model, reform or dynamics file reads a deprecated name, every shim is still defined and labelled deprecated.

Tests

  • Every YAML test that set is_child or is_adult as an input now sets ages and the programme inputs instead (134 lines across 12 files; 75 dead is_child/child_index inputs removed from the Scottish two-child-limit test).
  • New example tests for every behaviour change, with the arithmetic from the regulations in comments. Across the 47 changed or new YAML files: 416 cases, all passing on this branch; 177 of them fail on main 44240bd8 (the deliberate changes and new variables). before_after.py in the review folder runs each case on both.
  • Local runs on head f9814593 (targeted suites, because the host was heavily loaded; CI runs everything): policyengine-core test policyengine_uk/tests/policy passed all 1,477. The property, means-test income property, Housing Benefit property, code health, dynamics and parameter-metadata pytest files: 1,703 passed. The full pytest policyengine_uk/tests, including the microsimulation reform-impact regressions, is left to CI.

Downstream

The shims keep every downstream reader working. Migration issues: PolicyEngine/policyengine.py#537 (UK output columns, HBAI poverty groups, cliff denominator) and PolicyEngine/policyengine-uk-data#486 (supply is_hbai_dependent_child from the FRS; move calibration targets and imputation predictors onto the definitions of their own statistics).

Built with

Legal audit: 12 parallel auditors (one per programme family, plus tests, downstream and Axiom inventory) and adversarial citation verifiers. Implementation: this session plus gpt-6-astra Subfleet lanes for UC, Pension Credit, legacy benefits, LHA/benefit cap and the property tests, each reviewed and integrated here (for example the Pension Credit lane's earnings workaround was replaced by fixing pension_credit_earnings at source).

Axiom

axiom: encoded-correct: WRA 2012 s.39 couple and s.40 child (uk/statutes/ukpga/2012/5/39.yaml, 40.yaml + companion tests), UC Regs 2013 reg 5 QYP (uk/regulations/uksi/2013/376/5.yaml + test), reg 80A benefit cap amounts (.../376/80A.yaml + test), Sch 4 paras 27-28 shared accommodation (.../376/schedule/4/paragraph/27.yaml, 28.yaml + tests), SSCBA s.142 child (uk/statutes/ukpga/1992/4/142.yaml + test) | queued: TheAxiomFoundation/rulespec-uk#354 (merged; HB Regs Sch 3, SPC Regs Sch IIA and ITA s.55B in batch PE-UK-CHILD-DEFS; supervised encode pending d738 / Codex reset 10/3) and dispatch-ready pe-parity issues TheAxiomFoundation/rulespec-uk#355 (UC regs 3, 8), #356 (CB (General) Regs reg 3), #357 (HB regs 2, 13D, 19, 75CA), #358 (SSCBA s.137; IS regs 2, 14, Sch 2), #359 (SPCA ss.4, 5, 17), #360 (SPC reg 4A, Sch I paras 1, 2, 4), #361 (TCA ss.3, 8; CTC regs 2, 3, 5; WTC regs 4, 9, 11, 12, 14, 17), #362 (ITA s.55C), #363 (CPA 2014 ss.3, 6; SI 2015/448 regs 3, 9), #364 (Childcare Act 2016 s.1; SI 2022/1134 regs 14, 15), #365 (SI 2011/1986 regs 42, 45, 46), #384 (UC Sch 4 para 29 excepted persons, for the LHA disability exception); #357, #358 and #360 updated 2026-09-30 with HB reg 21(3), IS reg 16(4), the SPC Sch I para 1(1)(b)-(c) couple and carer limbs and reg 6(5), each with hand-computed companion cases | n/a: the HBAI variables are statistical definitions and the dynamics/private-school changes are modelling conventions.

🤖 Generated with Claude Code

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Heads-up from #1901 (pension-age Housing Benefit new claims): housing_benefit_eligible now has a pension-age route that reads is_adult, matching the member set is_uc_eligible and is_pension_credit_eligible use on main so no family gets both HB and UC.

This PR moves those two to is_claimant_or_partner, and its code-health test will flag the is_adult read. Whichever of the two merges second should switch the HB test to the same set:

claimant_or_partner = person("is_claimant_or_partner", period)
count = benunit.sum(claimant_or_partner)
pension_age = (count > 0) & (benunit.sum(claimant_or_partner & sp_age) == count)

That is also the legal test (SI 2014/1230 reg 6A(4): a single person, or a couple where both members, over the qualifying age). The pension_with_dependant shape in test_housing_benefit_pension_age_properties.py pins the HB/UC mutual exclusion, and it would then expect that family to get HB and no UC.

MaxGhenis and others added 16 commits September 30, 2026 11:45
…nd adult flags

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…plicit in modelling code

The HBAI modified OECD scale weights HBAI adults and dependent children, not an
age-18 split; results differ only in households with no one aged 18 or over.
The private school imputation and the labour supply elasticity groups keep an
explicit age band (no law governs them), with identical results.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eir children

Marriage Allowance is an election between spouses or civil partners (ITA 2007
ss.55B-55C) and the Tax-Free Childcare work condition applies to the person and
their partner (Childcare Payments Act 2014 s.3; SI 2015/448 regs 3 and 9). Both
now use is_claimant_or_partner instead of an age-18 test. The CPS marriage
reforms follow suit, and their child-age test now counts children under the
limit, as the parameters describe. The CGT marginal-rate index keeps its
explicit age-18 condition.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Care to Learn: the parent must get Child Benefit for the child, so the parent
no longer counts as their own child. Parents' Learning Allowance and Childcare
Grant: a dependent child of the student (SI 2011/1986 regs 42, 45, 46), with no
age limit of its own. Extended childcare: the income test applies to the parent
and partner only (Childcare Act 2016 s.1; SI 2022/1134 regs 14-15). Maintenance
loans drop a redundant age-18 test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…edit

The lone parent element, the disability and severe disability elements and the
eligibility routes now use the claimant or joint claimants (TCA 2002 s.3) and
responsibility for a child or qualifying young person under the CTC rules
(SI 2002/2005 regs 4, 9, 12, 17; SI 2002/2007 reg 3), instead of age-18 counts.
The childcare element counts children until the September after their 15th
birthday, or 16th if disabled (reg 14(3)-(4)).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Eligibility needs every claimant or partner at State Pension age (SPCA 2002
ss.1, 4(1A)); income, earnings and deductions count only the claimant and
partner (s.5); the carer and severe disability additions count only them
(Sch I paras 1, 4), and children no longer veto the severe disability addition
(Sch I para 2(2)(f)). Built with a gpt-6-astra subfleet lane; pension_credit_earnings
fixed at source instead of subtracting dependants' earnings downstream.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…itions

Income Support, income-based JSA, income-related ESA, Housing Benefit and council
tax reduction now use the claimant and partner (SSCBA 1992 s.137; IS Regs 1987
reg 2; HB Regs 2006 reg 2) and a child under 16 or Child Benefit qualifying young
person (IS reg 14; HB reg 19; JSA reg 76; ESA reg 2), instead of age-18 counts:
personal allowance ages, lone-parent status and the youngest-child test,
earnings disregards, disability premiums, HB childcare charges (reg 28 age
limits) and the capital owner weights. Built with a gpt-6-astra subfleet lane.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s own circumstances

The benefit cap's single rate applies to a claimant with no partner who is not
responsible for a child or qualifying young person (UC Regs 2013 reg 80A; HB Regs
2006 reg 75CA), and the LHA shared accommodation rate to a single renter under 35
with no child or qualifying young person and no non-dependant (UC Regs Sch 4
paras 27-29; HB reg 13D), instead of household counts of people aged 18+.
Built with a gpt-6-astra subfleet lane.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The age basic conditions apply to claimants only, with the observable
regulation 8 cases lowering the minimum age to 16 (WRA 2012 ss.3-4; UC Regs 2013
regs 3 and 8); the childcare work condition tests the claimant and partner
(reg 32); the household capital proxy is shared by claimants and partners (WRA
s.5; reg 18). Built with a gpt-6-astra subfleet lane.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
guarantee_credit was computed for every benefit unit below the minimum guarantee,
including working-age families, and the targeted childcare entitlement treated
it as a qualifying benefit. Guarantee credit is part of State Pension Credit
(SPCA 2002 ss.1-2), so it is now zero unless the unit is Pension Credit eligible.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… definitions

Exhaustive and Hypothesis checks that each programme's child and young-person
predicates match the encoded statutory limbs for every age and education
status, that HBAI types and benefit-unit classifications partition, that the
deprecated shims keep their age-18 formulas and agree with the explicit
age_under_18 predicates where the rule is age-only, and that adding a child
never changes who the claimant and partner are. The last property found that a
parent flag on an under-16 made an older student a dependant; an identified
parent must now be aged 16 or over. Tests built with a gpt-6-astra subfleet lane.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
housing_benefit_eligible (from #1901) read is_adult; like is_uc_eligible and
is_pension_credit_eligible it now tests the claimant and any partner (SI
2014/1230 reg 6A(4)), so a pensioner with an 18 or 19 year old dependant can
claim Housing Benefit and not Universal Credit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
is_claimant_or_partner treated every HBAI adult as a claimant or partner, so a
couple entered with an 18-year-old (no relationship or education inputs) had
three claimants: both parents drew Marriage Allowance from the child, and a
working lone parent failed the Tax-Free Childcare work condition because the
child counted as a partner who must work.

The claimant is now the benefit-unit head and the partner at most one other
HBAI adult: a member flagged as a parent, otherwise the eldest other adult who
is not presumed the head's child (under 20 and at least 16 years younger, a
PolicyEngine presumption held as parameters). Datasets and users can supply
the flag directly.

Tests: both review probes as default-input regressions, presumption cases, and
a Hypothesis property over arbitrary benefit units (at most two claimants, at
least one exactly when there is an HBAI adult, claimants are HBAI adults). The
Housing Benefit property fixture now sets is_claimant_or_partner from each
generated role.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ap and LHA category

One benefit cap and one LHA category serve Universal Credit and Housing
Benefit. Using only UC's qualifying young person moved HB families with a
Child Benefit young person (HB reg 19) onto the single cap, and 16-year-olds
outside education (UC reg 5(1)(a)) likewise. The family rates now apply if
either scheme's test is met.

Renters under 35 receiving attendance allowance, DLA care at the middle or
highest rate, or PIP daily living are excepted from the shared accommodation
rate (UC Sch 4 para 29(5)).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d children from legacy families

Sch I para 1(1)(b)-(c) and reg 6(5): a couple qualifies if both partners
receive a qualifying benefit and a carer benefit is paid for at most one of
them (double amount with none, single with one), or if one does and the other
is blind (single amount). Removing the child veto had extended the addition
to couples where only one partner qualified.

A child or young person placed with the family by a local authority is not a
member of the household for the legacy benefits (IS reg 16(4), HB reg 21(3)).

Changelog: Guarantee Credit gating and the Housing Benefit pension-age route.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit that referenced this pull request Sep 30, 2026
Adds YAML cases where an 18 or 19 year old qualifying young person is in the
family: they are neither a partner nor a non-dependant, so they cannot make
a couple qualify, be the blind partner treated as absent, or stop a lone
parent qualifying. The legacy-premium fixtures from #1896 now use PIP daily
living at the enhanced rate, which qualifies for the premium and is also
severe for tax credits. The oracle property draws carers less often and has
explicit double-rate and blind-partner examples, with events that show which
branches ran; the Pension Credit differential says it compares two encodings
of one rule, on the cases every version of that addition agrees on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit that referenced this pull request Sep 30, 2026
A benefit-unit member aged 18 or over who is neither the claimant, the
partner, nor a child or qualifying young person (HB Regs reg 19; SSCBA
s.142) is a non-dependant under reg 3 and bars the premium; the test
previously exempted every benefit-unit member. Adds a YAML case for an
18-year-old not in education, and gives #1896's 19-year-old fixtures the
entry-condition input that makes them qualifying young persons.

Documentation now states the carer condition as the Regulations do (caring
for a single claimant; the couple rates), notes that only the claimant's
blind partner is treated as absent and that the model assumes the
qualifying partner claims (HB Regs reg 82(1)), lists child disability
payment among the unmodelled Scottish benefits, notes that the tax credit
flag also gates UC's higher disabled child addition, and fixes the JSA
pinpoint. The property tests compute each before/after pair in one
simulation, and the Pension Credit differential now covers carers and
couples with one qualifying partner, since #1896's addition applies the
same rules.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

The failing Test check (run 36756004260) is tests/test_carer_support_payment.py::test_csp_counts_for_pension_credit_carer_additions_and_blocks_severe_disability at line 62: severe_disability_minimum_guarantee_addition is £4,329.04 where the test expects 0.

The scenario is one adult who receives Attendance Allowance and is also paid Carer Support Payment (care_hours 40). Commit 9b13503 in this PR deliberately stops a person's own carer benefit barring their addition. SPC Regs 2002 Sch I para 1(1)(a)(iii) bars it only where someone is paid a carer benefit "in respect of caring for him", and a claimant can't be their own carer. So the test encodes the old any-carer-in-the-unit assumption, and its expectation should flip.

Suggested patch:

  • rename the test to test_csp_counts_for_pension_credit_carer_additions;
  • assert severe_disability_minimum_guarantee_addition equals parameters.gov.dwp.pension_credit.guarantee_credit.severe_disability.addition * 52;
  • add a two-person case where the partner is paid CSP for caring for the claimant, which should give the single rate or nil, depending on whether the partner also qualifies.

#1946 and #1966 are stacked on this PR and inherit the failure until it is fixed here.

🤖 Generated with Claude Code

… disability addition

Commit 9b13503 stopped a person's own carer benefit barring their Pension
Credit severe disability addition (SPC Regs 2002 Sch I para 1(1)(a)(iii):
only a carer benefit paid for caring for them bars it). The Carer Support
Payment test still expected the old any-carer-in-the-unit bar. Flip it,
and add couple cases: both partners qualifying with a carer benefit paid for
one gives the single amount (reg 6(5)); one partner qualifying and the other
not blind gives nothing (para 1(1)(c)).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Pushed 143cc3c to this branch, applying the patch in the comment above.

  • Rename. test_csp_counts_for_pension_credit_carer_additions_and_blocks_severe_disability is now test_csp_counts_for_pension_credit_carer_additions. It expects the severe disability addition (addition × 52), matching 9b13503 and SPC Regs 2002 Sch I para 1(1)(a)(iii).
  • New couple test. It covers two cases:
    • both partners qualify and one is paid Carer Support Payment: the single amount (reg 6(5));
    • only one partner qualifies and the other is not blind: nothing (para 1(1)(c)).

pytest policyengine_uk/tests/test_carer_support_payment.py: 5 passed locally. That was the only failure in this PR's Test job (run 36756004260). Pushed on behalf of the sessions whose PRs are stacked here (#1946, #1966).

🤖 Generated with Claude Code

MaxGhenis added a commit that referenced this pull request Oct 1, 2026
Adds YAML cases where an 18 or 19 year old qualifying young person is in the
family: they are neither a partner nor a non-dependant, so they cannot make
a couple qualify, be the blind partner treated as absent, or stop a lone
parent qualifying. The legacy-premium fixtures from #1896 now use PIP daily
living at the enhanced rate, which qualifies for the premium and is also
severe for tax credits. The oracle property draws carers less often and has
explicit double-rate and blind-partner examples, with events that show which
branches ran; the Pension Credit differential says it compares two encodings
of one rule, on the cases every version of that addition agrees on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit that referenced this pull request Oct 1, 2026
A benefit-unit member aged 18 or over who is neither the claimant, the
partner, nor a child or qualifying young person (HB Regs reg 19; SSCBA
s.142) is a non-dependant under reg 3 and bars the premium; the test
previously exempted every benefit-unit member. Adds a YAML case for an
18-year-old not in education, and gives #1896's 19-year-old fixtures the
entry-condition input that makes them qualifying young persons.

Documentation now states the carer condition as the Regulations do (caring
for a single claimant; the couple rates), notes that only the claimant's
blind partner is treated as absent and that the model assumes the
qualifying partner claims (HB Regs reg 82(1)), lists child disability
payment among the unmodelled Scottish benefits, notes that the tax credit
flag also gates UC's higher disabled child addition, and fixes the JSA
pinpoint. The property tests compute each before/after pair in one
simulation, and the Pension Credit differential now covers carers and
couples with one qualifying partner, since #1896's addition applies the
same rules.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 1, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant