Repository navigation
Give Universal Credit and Housing Benefit their own benefit cap and LHA shared-accommodation rules - #2089
Conversation
…HA shared-accommodation rules One benefit cap (rate, exceptions, reduction) and one LHA category served both schemes although the law differs. Each scheme now has its own: - UC: uc_benefit_cap (reg 80A), is_uc_benefit_cap_single_claimant_rate (a reg 3(3) single claim is single), is_uc_benefit_cap_exempt_earnings (reg 82), is_uc_benefit_cap_exempt_specified_benefit (reg 83, "a claimant"), uc_benefit_cap_reduction (reg 81, less the childcare costs element). LHA_category / is_lha_shared_accommodation_rate_specified_renter are UC's (Sch 4 paras 27-29). - HB: housing_benefit_benefit_cap (reg 75CA), single claimant per reg 2(1), exceptions 75E (WTC) and 75F (claimant or partner), no cap under the pension-age regulations (reg 5), housing_benefit_benefit_cap_reduction (75D, keeping the reg 75 minimum). housing_benefit_LHA_category, is_housing_benefit_young_individual and housing_benefit_LHA_rate follow reg 13D(2)(a)(i), with names and helpers shared with #2006. - universal_credit and housing_benefit read their own reduction; benefit_cap_reduction is their sum. The claims_legacy_benefits stopgap from #2084 is gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ions and LHA category Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…B LHA rate; docs and changelog Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…case, verbatim reference award - programs.yaml: the Benefit Cap entry named the removed benefit_cap; it now reads benefit_cap_reduction and says each scheme has its own cap. - Armed forces independence payment lifts both caps: UC reg 83(1)(c) (reg 2's "attendance allowance") and HB reg 75F(1)(ea). - The HB-only young person LHA case supplies the two bedrooms both schemes' size criteria give (UC Sch 4 para 10(1); HB reg 13D(3)(b)): C. - reference_universal_credit is the parent formula, protected floor included; the differential excludes AFIP families (an intended change). - Document that uc_benefit_cap_reduction is the reg 81 amount, which can exceed the award; BRMA_LHA_rate is the UC category's weekly rate. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Coordination from #2084, which this PR is stacked on. #2084's head moved to
When #2084 is merged into this branch, keep this PR's deletion of the helpers. Then check that the per-scheme variables pass those two YAML cases, since they pin the UC-vs-HB routing the split has to keep. #2084's round-3 review (subfleet 20261003-101137-reg33-review-r3) is reviewing |
|
Overlap with #1978 (Count only claimants' income in Universal Credit), for whichever of the two merges second. #1978 limits two of the things this PR moves to the claimant and partner (
The intended end state is this PR's split, with both new variables summing person-level amounts over #1978's head is |
#2084 has merged, so this branch now targets main. Conflict resolutions: - LHA (#2006, #2134, #2022): main's housing_benefit_LHA_category, housing_benefit_LHA_rate, housing_benefit_severe_disability_premium_applies, LHA_cap, BRMA_LHA_rate, LHA_category and uncapped_BRMA_LHA_rate. This branch's reg 3(3) lines stay in is_lha_shared_accommodation_rate_specified_renter (#2030 is still open, so lha_renter_has_non_dependant and the union responsibility term stay). Its expectations in LHA_claimant_composition.yaml and housing_benefit_lha_order.yaml; the two HB categories this branch added there are now C under main's HB size criteria (reg 13D(3)(b)). - #1944: housing_benefit_pension_age_regulations_apply is main's. Its edit to the deleted is_benefit_cap_exempt_other is dropped. Its tests now read the per-scheme variables; the property file's "before" reform adds the age test to each scheme's exceptions. - #1978: the UC earnings exception and the capped total (benefit_cap_welfare_benefits) sum over is_uc_assessed_claimant. - Carer's Allowance overlap: both specified-benefit exceptions read is_entitled_to_carer_benefit (UC reg 83(1)(i)-(ia), HB reg 75F(1)(h)-(ha)). - #2084 (final head): the stays_on_legacy_benefits helpers stay deleted; its two routing cases are rewritten on the per-scheme variables. - SI 2014/1230 reg 60C: is_uc_benefit_cap_exempt_qualifying_age lifts the UC cap where every claimant has reached the qualifying age for State Pension Credit. That keeps the result #1944 pinned for such awards (inputs only; the model's UC eligibility needs a claimant under that age). - Tests main added that read the removed shared variables now read the per-scheme ones. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tion - housing_benefit_lha_category.yaml: main's severe disability premium counts an adult outside the family only as the liable family's non-dependant (#2006). The case now makes the claimant's family the household head's, so the other adult is a non-dependant (HB reg 3) and defeats Sch 3 para 14(2)(a)(ii), as the case intends. - housing_benefit_on_passporting_benefit.yaml (main): universal_credit reads uc_benefit_cap_reduction, so the case sets that input. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…oom counts agree The old shared category read the Universal Credit size criteria (LHA_allowed_bedrooms). Since #2006, Housing Benefit has its own count (HB Regs 2006 reg. 13D(3), housing_benefit_LHA_allowed_bedrooms), which gives a bedroom to a young person the Universal Credit count leaves out. The differential now compares Housing Benefit's category with the reference only where the two counts agree, and the examples check that the lone-parent case reaches that difference (HB category C). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only Universal Credit's shared-rate test (is_lha_shared_accommodation_rate_specified_renter) reads it; Housing Benefit's LHA category reads is_housing_benefit_young_individual and housing_benefit_has_non_dependant. P3 from the delta review of 85d9be9. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…reg 75F(1)(g)) UC Regs 2013 reg 80(2A) counts Housing Benefit as nil in the Universal Credit total, so uc_benefit_cap_reduction takes it out of benefit_cap_welfare_benefits, which keeps it for the Housing Benefit cap (HB Regs 2006 reg 75C(2)(b)). HB reg 75F(1)(g) lifts the Housing Benefit cap where the claimant is receiving Universal Credit: is_housing_benefit_benefit_cap_exempt_specified_benefit now includes a family with Housing Benefit and Universal Credit before the cap. housing_benefit_eligible rules out a family that claims Universal Credit, so no computed family gets both today and no baseline result changes; the rules matter once a family is paid both (specified or temporary accommodation, #1910). Reg 75C(2)(a) (specified-accommodation HB counted as nil) is not applied: in_specified_or_temporary_accommodation does not separate specified from temporary accommodation. Vahid Ahmadi's finding 3 on #2089. Tests: two YAML cases (each fails on the previous formulas), a property file (test_benefit_cap_uc_and_hb_properties.py), and the split property file's reduction invariant now checks reg 80(2A) and 75F(1)(g) in place of asserting that no family gets both. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
juaristi22
left a comment
There was a problem hiding this comment.
Reviewed ea46f7c3ec56bc757e1d1f9ac5ca07e26de50877 against merge base 7e10ccd98326b6c9acd244191bb4636985e710b0 with separate code/test and policy/source roles. The earlier integration and dual-award concerns are addressed; no new blocking formula defect was established. Two points remain to address before treating the review record as complete:
- A1 — Refresh the description. Its opening still names
04ac713fa, says the diff is byte-identical to the old review, and states that UC/HB never coexist. This head deliberately handles supplied dual awards: HB is excluded from UC's cap total and HB is exempted when an established pre-cap UC award exists. Update the scope/invariant sections, distinguish the remaining formula-derived eligibility limitation, and label old-head impact/validation tables. - A2 — Carry forward the dated earnings-threshold correction.
is_uc_benefit_cap_exempt_earnings.pystill uses £10,152. UC reg82(1)(a) ties this to16hours/week at the minimum-wage rate; £12.71 from April2026 implies £10,574.72/year under that conversion. £10,400 of actual earnings therefore lies on opposite sides of the tests. This is Vahid's inherited nonblocking concern, not a newly introduced regression. Coordinate #1820's dated parameter into this renamed file or record the landing dependency.
The split now excludes HB from the UC cap under UC80(2A) and prevents a second HB cap under HB75F(1)(g). The DWP explanatory memorandum, paragraph7.2 supports using established pre-cap UC entitlement even where the cap later reduces UC to nil. That is distinct from unclaimed notional eligibility.
Validation: two independently executed final-income controls passed on Core3.33.0: managed migration preserves the same cap/final award as ordinary take-up; adding £10,000 supplied HB leaves the UC cap unchanged and raises final household income by £10,000. The local broad changed-file rerun hit its540s bound at25%, without a final pass count; it is not claimed as passing. Complete hosted YAML/four Python shards and required checks are green at this exact head. The source review validated28official originals, including the decisive PDF page. Private population impact was not rerun; the combined #1819/#1820 trees were not tested. The substantive Axiom status is present.
Before landing, coordinate #1819's competing uc_benefit_cap_reduction definition and #1820's threshold fix. Current GitHub mergeability was temporarily UNKNOWN after main advanced, so this is not a declaration that every merge gate has passed. Review only; no branch changes or merge performed.
…into uc-hb-split-shared-cap-lha-rules No conflicts. Main's two edits to files this PR also changes (test_benefit_cap_specified_benefits_properties.py: REBALANCED_YEARS from REBALANCING_YEARS; test_legacy_award_readers_properties.py: comment) merged automatically. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
juaristi22
left a comment
There was a problem hiding this comment.
Review status: COMPLETE
Review severity: COMMENT
Reviewed head: 4cfc373c4228c756ab7878ef27cfff91dbd298ab (main a94c65df integrated).
The incremental review found no new critical findings or material evidence gaps. All 86 focused cases passed, including managed migration, supplied UC/HB awards with one cap, and protected/new LCWRA claimants through final UC and household income in 2026, 2029, 2030 and 2032.
Two prior follow-ups remain STILL OPEN at their existing SHOULD ADDRESS severity:
- A1: update the description's old head/equivalence claims and its statement that UC/HB awards never overlap.
- A2: the renamed UC earnings-exemption file still uses £10,152; coordinate the dated threshold from #1820. This remains inherited feedback, with no new critical escalation.
Local checks used Core 3.33.0 / Hypothesis 6.168.2, rather than locked 3.33.2 / 6.169. Hosted Python 1/4 and 2/4 and the required Result were still pending at the final guard; no CI failures were observed. The #1819/#1820 landing coordination remains, and combined dependency trees were not tested.
- P3-1: document that the HB cap rate counts a 16-year-old for the year (has_sixteen_year_old_dependant) while the HB reg 75F exceptions read the model's Child Benefit qualifying young person, which leaves out one outside education; in law one status decides both (CB (General) Regs 2006 regs 5 and 7), and the model has no school-leaver terminal date (#2287). No formula changes: main's #2076 case "A 16-year-old out of education with armed forces independence payment does not lift the cap" pins this reading of reg 75F(1)(ea). - P3-2: the changelog said AFIP "now lifts both caps"; main already lifts them. Against main the UC exception narrows to a claimant's AFIP (UC reg 83(1)(c) with reg 2); HB keeps the young person's (reg 75F(1)(ea)). - P3-3: benefit_cap_welfare_benefits' documentation now says the total includes UC and HB before the cap, which uc_benefit_cap_reduction relies on for reg 80(2A); the capital-income property test's comment no longer names exemption routes the UC exemption stopped reading. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No conflicts. #2242 uplifts the UC standard allowance (parameters, the rebalancing uprating, its test); it touches no file this PR changes, and nothing it adds reads a variable this PR removes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ing counts The e640e0a delta review's P3: the Child Benefit education or training condition (meets_qualifying_young_person_education_or_training_condition_for_child_benefit) accepts approved training as well as non-advanced education, so "outside education" overstated who the HB exceptions leave out. Docs only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@vahid-ahmadi, thanks for the review of 1. Integrate #2076 and #2399 (must): done.
2.
3. UC and HB both (should): done in
4. The reg 82 threshold is a hardcoded £10,152 (should): answered in writing; the landing dependency is recorded in the description.
Since |
|
@juaristi22, thanks for both rounds, and for the final-income controls. Where your two follow-ups stand at head A1, refresh the description: done.
A2, the reg 82 threshold: recorded as a landing dependency, not changed here.
The #1819 name clash is answered in the Coordination section and in my reply to Vahid: this PR keeps |
juaristi22
left a comment
There was a problem hiding this comment.
Reviewed the replies and revised description at e82c4acacafd516836ca4cc1797ea4536c3e9d63; both independent review roles are complete with no new findings. The previously reviewed code head is unchanged.
A1 is resolved: the description now identifies the current head, distinguishes supplied dual UC/HB awards from formula-derived eligibility, and corrects the reduction invariants and validation provenance.
A2 is resolved through the original request's record the integration dependency alternative. The £10,152 literal remains unchanged; this does not certify the dated threshold as fixed. Keep #1820's parameter/port and #1819's gross-versus-floor-bounded variable naming explicit in landing coordination.
No new model run or private impact validation was performed for this prose-only follow-up; earlier code/source checks and their limitations remain. All current checks are green and GitHub reports a clean merge, but combined dependency integration and Vahid's separate feedback still need coordination before calling this merge ready.
Review r11 (Opus and GPT-6.1 Sol) on 871e46d: main's benefit cap readers (#2076, #2089) called award_of_members on esa_income and jsa_income. Under disable_simulated_benefits the held total matches neither of its readings after the dataset year, so another member's held award was read as the couple's: it raised benefit_cap_welfare_benefits and could exempt a claimant with an ESA support component who receives no ESA. - utils/benefit_unit.py: award_of_couple reads claimant_or_partner_* wherever the rule's couple is the claimant and partner, and award_of_members for any other couple (a UC couple with is_uc_claimant entered). CLAIMANT_OR_PARTNER_AWARDS moves here; the reform imports it. - benefit_cap_welfare_benefits and both specified-benefit exemptions read award_of_couple. - The reform's docstring says it reads its inputs when it is applied, so a region a scenario's after-load modifier or set_input changes later is not followed; applying the reform after the change reads it (r11 Sol finding 2, Opus nit 4). New test for that route. - Changelog: the first bullet no longer claims what #2047 shipped (r11 Opus finding 2); new bullet for the benefit cap. - New test_disable_simulated_benefits_benefit_cap.py: metamorphic (another member's report never changes the cap, reform on), differential against main's replaced reader (reform off), the fallback couple, and an entered award reaching the cap. Each reader's mutant fails it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…m test Main now has uc_benefit_cap_reduction (#2089) as the gross regulation 81 amount, so the floor-bounded amount this PR adds becomes uc_benefit_cap_reduction_after_floor and reads it as its gross input. universal_credit subtracts the floored amount plus uc_deductions. Both components now use claims_universal_credit, the award's own claim test, instead of would_claim_uc, so a family that claims at legacy benefit closure keeps the benefit cap and its deductions. A YAML case pins that route through final UC at the reviewer's figures. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#2089 split the benefit cap by scheme and deleted the shared is_benefit_cap_exempt_health_disability. Its UC and HB specified-benefit variables already place armed forces independence payment as this PR did (UC Regs 2013 regs 2, 83(1)(c); HB Regs 2006 reg 75F(1)(ea)), so the deleted file is dropped and the two property tests take main's version. - The earnings threshold parameter follows the move into is_uc_benefit_cap_exempt_earnings. - The earnings YAML cases move to is_uc_benefit_cap_exempt_earnings.yaml under the new variable names; the AFIP cases there are dropped, main covers them, except the paired final-award cases, kept in benefit_cap_specified_benefits.yaml. - test_uc_single_claim_properties.py keeps the partner AFIP example, asserted against the scheme-split variables. - test_benefit_cap_lha_scheme_split_properties.py: the old shared earnings reference reads the threshold parameter instead of 10_152. - Changelog no longer claims the AFIP fix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…2015, #2027, #2089 - HB: each non-dependant family's amount (one per couple, exemptions, claimant exemption) now composes with #2006: only non-dependants of the household head count, and each family liable for the rent bears its share_of_household_rent. - CTR: each applicant's scheme follows its own family (#2015, council_tax_reduction_pensioner). The scheme-dependent rules move to _national_non_dependants.py, taking the applicant's scheme as an argument. Person-level variables report the household head's family's scheme; council_tax_reduction_non_dep_deductions recomputes under an applicant's own scheme where it differs, then applies the joint-liability share and the per-family applicant exemption, which now applies in the national schemes too. - The UC after the cap uses #2089's uc_benefit_cap; main's uc_benefit_cap_reduction counts Housing Benefit and would be circular. - Tests: main's stopgap investment-income cases are rewritten under reg 74(1)(b) / para 8(2); main's cannot-claim case now carries the lowest deduction; the 2014 cases are removed (main lacks 2014 parameters). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#2089 replaced the shared is_benefit_cap_single_claimant_rate with is_uc_benefit_cap_single_claimant_rate and its Housing Benefit counterpart. The lone-parent case asserts the UC rate, which is still false: the 16-year-old outside education is a qualifying young person the claimant is responsible for. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main (582b863) now has #2076 (benefit cap person scopes; the work allowance reads uc_limited_capability_for_work), #2089 (separate UC and HB caps) and the UC Act 2025 LCWRA freeze. Resolution: - is_uc_work_allowance_eligible: both changes, as agreed on #2076. Limited capability for work (reg. 22(1)(b)) of an assessed claimant, which keeps the other member of a single claim (reg. 22(3)). - uc_LCWRA_element.yaml: main's 2027-2029 freeze cases and this branch's claimant-only cases, both kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Base is
main. The head ise82c4acac, which merges main ate7610ac52(#2242). #2084 (UC reg 3(3) single claims), which this PR was stacked on, merged as4ed5b3ce4. Since Vahid Ahmadi's review atb7e0b2373:270bfaabf,85d9be9ff);ea46f7c3e);5f7a7d108,4cfc373c4,e640e0a81);ea048820c,ab514f5b8ande82c4acacanswer review P3s in documentation only.Main has since moved to
14999dc03(#2436, dated-reform backdating; #2440, pension relief in adjusted net income). Neither touches a cap, LHA, UC or HB file. #2440 editstest_trading_loss_properties.py, which this PR also edits (one renamed variable); the hunks are separate, and git merges them without conflict.What was wrong
On main, one set of variables serves both Universal Credit and Housing Benefit, although the two schemes' rules differ:
is_benefit_cap_single_claimant_rate/benefit_capuse one "single claimant" test, with the family rate wherever either scheme's child or young-person test is met. UC Regs 2013 reg 80A(2) and HB Regs 2006 reg 75CA(2) each define it their own way.is_benefit_cap_exempt_health_disability,_otherand_earningsare the union of both schemes' grounds:housing_benefit_pension_age_regulations_apply, HB reg 5) also serves as the UC age test. The UC age exception is SI 2014/1230 reg 60C, which turns on the claimants alone.benefit_cap_reductionserves both schemes. It applies neither UC reg 81 (the childcare costs element comes off) nor HB reg 75D(2) (the 50p weekly minimum stays).universal_creditandhousing_benefitboth subtract the onebenefit_cap_reduction, whose total includes HB. A family given both awards has its HB counted in the UC total, against UC reg 80(2A), and has the reduction taken off both awards. The model's HB eligibility rules out a family that claims UC, so only supplied awards reach this today; Abolish working-age Housing Benefit from 1 July 2026 (NI 1 October 2026) #1910 would compute both.is_lha_shared_accommodation_rate_specified_renter, still applies a reg 3(3) single claim only when the family is not staying on legacy benefits, and leaves AFIP out of the para 29(5) list.#2084 gated the reg 3(3) consequences in these shared variables on the family staying on legacy benefits, as a stopgap. That was wrong for any family whose legacy status did not match the scheme being calculated.
The law
legislation.gov.uk data.xml, current text, fetched 2026-10-02 (SI 2014/1230 regs 60A and 60C fetched 2026-10-09).
Who is a single claimant
The welfare benefits counted
Exceptions
Reductions
Shared accommodation
What this PR does
uc_benefit_cap(reg 80A)housing_benefit_benefit_cap(reg 75CA)is_uc_benefit_cap_single_claimant_rate: not joint claimants (a reg 3(3) single claim is single), not responsible for a child or QYP under UC's own testis_housing_benefit_benefit_cap_single_claimant_rate:is_single_person(reg 2(1)); a reg 3(3) couple is a coupleis_uc_benefit_cap_exempt=_earnings(reg 82: #2399's measure, the assessed claimants'uc_individual_earned_income_before_mif) or_specified_benefit(reg 83: the LCWRA or carer element in the award; a claimant's ESA with the support component; a claimant's benefits, AFIP included as attendance allowance (reg 2); UC's own child and QYP tests; the reg 3(3) other member is not a claimant) or_qualifying_age(SI 2014/1230 reg 60C: the single claimant, or both joint claimants, at the qualifying age for State Pension Credit). No WTC exception.is_housing_benefit_benefit_cap_exempt=_working_tax_credit(75E) or_specified_benefit(75F: the claimant's or partner's ESA with the support component and other benefits; AFIP, for a young person too; HB's own child and young-person tests; 75F(1)(g), a family with HB and UC before the cap) orhousing_benefit_pension_age_regulations_apply(reg 5). No earnings, LCWRA or carer-element exception.uc_benefit_cap_reduction: the excess of the welfare benefits, with HB counted as nil (reg 80(2A)), less the childcare costs element, on an award only (regs 78(1), 81)housing_benefit_benefit_cap_reduction: the excess, leaving 50p a week (regs 75, 75D)universal_credit,uc_deductions,uc_has_deductionhousing_benefitLHA_categorywithis_lha_shared_accommodation_rate_specified_renter(Sch 4 paras 27-29): reg 3(3) applied whatever legacy benefits the family reports; AFIP added to the para 29(5) list (reg 2)housing_benefit_LHA_category(#2006), unchangedOther changes:
award_of_members,is_payee_of_couple_award). The LCWRA and carer elements count when they are in the award, including an entered element (main'selement_included).benefit_cap_welfare_benefitsis main's capped total, unchanged:benefit_cap_couple, withaward_of_membersfor income-based JSA and income-related ESA (WRA 2012 s. 96(1); UC reg 80(1)).is_uc_benefit_cap_exempt_earningsis Fix benefit-cap statutory-pay earnings exemption #2399's formula, unchanged, including its threshold of £10,152 a year._qualifying_agereadsis_uc_single_or_joint_claimant(WRA 2012 s. 40). A partner who cannot be a joint claimant is not a claimant, so a 70-year-old claiming as a single person beside a 50-year-old partner excluded by reg 3(3) is not capped; a mixed-age joint claim is. The model's own UC eligibility needs a claimant under the qualifying age, except for a reg 60A claim by a working tax credit recipient whose tax credits closed (claims_uc_at_legacy_closure), so otherwise only a supplied award reaches this exception. The model has no qualifying-claim input: it treats such an award as a reg 60C case, because s. 4(1)(b) bars any other claim by those claimants. This keeps the result Apply the benefit cap to mixed-age couples on Universal Credit, and keep them off pensioner Council Tax Reduction #1944 pinned for these awards inbenefit_cap_pension_age.yaml, which main reaches through the HB reg 5 test.is_entitled_to_carer_benefit(UC reg 83(1)(i)-(ia); HB reg 75F(1)(h)-(ha): "is entitled to"), as main's shared rule does.benefit_cap_welfare_benefits, HB at its amount before the cap under reg 75C(2)(b)) serves both caps.uc_benefit_cap_reductiontakes HB out of it (UC reg 80(2A)). The HB exception includes a family with HB and UC before the cap (HB reg 75F(1)(g)), so its HB reduction is nil. That reads "receiving" as an award of UC before the cap, so a UC award the cap reduces to nil still lifts the HB cap. HB reg 2(3B) treats a person as on UC "whether it is in payment or not", and juaristi22's review cites the DWP explanatory memorandum to SI 2014/771 (para 7.2) for the same reading. Requiring HB before the cap keeps a UC-only family's HB exception flags as they were. Only supplied awards reach this until Abolish working-age Housing Benefit from 1 July 2026 (NI 1 October 2026) #1910 (see "What was wrong").benefit_cap_reductionremains, as the sum of the two schemes' reductions; uk-data's DWP benefit-cap calibration targets read it. A family with neither award now has no reduction. The UC part is the reg 81 amount, which can exceed the award before the cap (universal_creditfloors the award at nil). That predates this PR; bounding the reported amount changes uk-data's monetary inputs, so it is a follow-up.has_sixteen_year_old_dependant), since annual ages cannot place UC reg 5(1)(a)'s 1 September or the Child Benefit terminal dates. UC's exceptions count that 16-year-old too; HB's read the model's Child Benefit qualifying young person, which leaves them out. In law one status decides both under HB. Main's Lift the benefit cap only for the support component and the people HB reg 75F and UC reg 83 name, and cap only the family's benefits #2076 AFIP case pins the HB exceptions' reading, and the fix belongs with Child Benefit qualifying young person omits the school-leaver conditions (Child Benefit (General) Regulations 2006 regs 4, 5 and 7) #2287's school-leaver rules.claims_legacy_benefitsstopgap helpers inutils/uc_work_related_requirements.pyare gone.benefit_cap,is_benefit_cap_exempt,is_benefit_cap_exempt_earnings,is_benefit_cap_exempt_health_disability,is_benefit_cap_exempt_other,is_benefit_cap_single_claimant_rate. The program registry (programs.yaml, served at/uk/metadata) now namesbenefit_cap_reductionfor the Benefit Cap. Three other registry entries name variables that do not exist on main (JSA,ESA,DLA); they are a separate follow-up with a registry test.benefit_cap_reductionas an input (the awards no longer read it), now use the per-scheme ones:benefit_cap/(Lift the benefit cap only for the support component and the people HB reg 75F and UC reg 83 name, and cap only the family's benefits #2076, Fix benefit-cap statutory-pay earnings exemption #2399, Apply the benefit cap to mixed-age couples on Universal Credit, and keep them off pensioner Council Tax Reduction #1944),dependants_income.yaml,carers_allowance_overlapping_benefits.yaml,state_pension_credit_qualifying_age.yaml,council_tax_reduction_pensioner.yaml,housing_benefit_on_passporting_benefit.yaml,legacy_award_readers/passports.yaml,uc_trading_loss.yaml, and the UC claimant and legacy-closure files.test_benefit_cap_and_ctr_pension_age_properties.py,test_benefit_cap_specified_benefits_properties.py,test_data_built_imputations.py,test_legacy_award_readers_properties.py,test_state_pension_credit_qualifying_age.py,test_trading_loss_properties.py,test_uc_claimant_income_properties.py,test_uc_company_owner_properties.py,test_uc_income_from_capital_properties.py,test_uc_legacy_closure_properties.pyandtest_uc_statutory_pay_properties.py.test_benefit_cap_and_ctr_pension_age_properties.py's "before Apply the benefit cap to mixed-age couples on Universal Credit, and keep them off pensioner Council Tax Reduction #1944" reform now adds the old any-member-over-State-Pension-age test to each scheme's exceptions.LHA and #2006/#2030. #2006 merged with the HB LHA names this PR had converged on, so main's
housing_benefit_LHA_category,housing_benefit_LHA_rate,is_housing_benefit_young_individual,housing_benefit_severe_disability_premium_applies,housing_benefit_LHA_allowed_bedroomsandLHA_capstand unchanged. This PR changes only UC's shared-rate test. It keeps the household-composition proxy (lha_renter_has_non_dependant), and the test still reads responsibility under either scheme: a dependant under one scheme only is the other scheme's non-dependant, which the proxy does not identify. #2030 (open) replaces both with each scheme's own non-dependant test.Not modelled (as before): the UC grace period (reg 82(1)(b)), the HB 39-week grace period (75E(3)-(5)), the weekly rounding of HB's relevant amount (75CA(1)), the reg 75 non-payment of HB below 50p, the para 29 exceptions other than disability benefits, and whether a claim is a reg 60C qualifying claim. Also HB reg 75C(2)(a), specified-accommodation HB counted as nil: main's input
in_specified_or_temporary_accommodation(#2123) does not separate specified from temporary accommodation, so that HB counts at its amount before the cap.Impact
Real Enhanced FRS runs (r10), one at a time. Base is main
e7610ac52, the main this head merged; branch is the heade82c4acac. Private copy ofenhanced_frs_2024_25.h5, sha256 e433e532…. Weighted £m a year; records are survey records.benefit_cap_reduction, base → branch4cfc373c4(r9, base maina94c65df9), this PR's UC change is identical in 2025-28 and slightly higher in 2029-30 (+£26.44m and +£28.37m then). Main's UC standard allowance uplift (Apply the Universal Credit Act 2025 standard allowance uplifts to 2029-30 #2242), merged ine640e0a81, raises UC before the cap on both sides from 2027: in 2027-28 that changes main's capped totals but not this PR's effect.benefit_cap_reductionfalls by the UC change. uk-data's DWP benefit-cap calibration targets read it. For 2025 the count of capped benefit units is unchanged and the total falls by £23.0m (3.8%).benefit_cap_reductionwithout an award;LHA_capanduc_LHA_capare unchanged everywhere.Scripts and outputs:
impact/in the handover folder (dataset_impact_r3.py,compare_r3.py,run_r10.sh,table_rows.py,r10/branch_vs_base.json).Tests
gov/dwp/benefit_cap_by_scheme.yaml(22 cases). Each scheme's exceptions:housing_benefit/housing_benefit_lha_category.yaml(9 cases): AFIP excepted under UC Sch 4 para 29(5)(b) with reg 2 and under HB Sch 3 para 14; HB young individual at 30 and at 35; para 14(2)(b) for a couple; an adult non-dependant defeats the premium unless they receive a qualifying benefit (para 14(4)); another family's claimant in the household; an HB-only young person blocks both shared rates.gov/dwp/benefit_cap.yaml(18). The reg 3(3) couple gets UC 14,753 and HB 22,020; so does the HB-only 19-year-old.LHA_claimant_composition.yaml(17). The reg 3(3) couple gets UC A and HB B. Two HB categories this PR had added are C under main's HB size criteria (Give sharers, boarders and lodgers their own rent, tenure and LHA category #2006; HB reg 13D(3)(b)).universal_credit/claims_as_single_person.yaml(33). The other member's PIP lifts the HB cap (75F) but not the UC cap (83); earnings lift the UC cap but not the HB cap; Model a Universal Credit claim by a member of a couple as a single person (UC Regs 2013 reg 3(3)) #2084's "reports HB but claims UC" and "stays on legacy benefits" cases on the per-scheme variables.test_benefit_cap_lha_scheme_split_properties.py(7 tests, derandomised, 1 to 6 families per example, plus eight explicit example families: reg 3(3) on UC and on legacy benefits, reg 81, an HB-only young person, AFIP, a mixed-age couple, LCWRA on HB and reg 75D(2); the other differences are pinned in YAML): differential tests against the shared formulas at Model a Universal Credit claim by a member of a couple as a single person (UC Regs 2013 reg 3(3)) #2084's head (17b9b8a), re-added underreference_names through a structuralReform, so one simulation computes old and new for the same families. The return expressions are verbatim; the copies differ in the names they read, the inlined stopgap helpers and the unused intermediate values they drop. Those reference formulas predate Lift the benefit cap only for the support component and the people HB reg 75F and UC reg 83 name, and cap only the family's benefits #2076 and Fix benefit-cap statutory-pay earnings exemption #2399; the per-person scopes those PRs added are pinned by their own converted YAML and property files (benefit_cap_specified_benefits.yaml,benefit_cap_capped_total.yaml,benefit_cap_earnings_exception_earned_income.yaml,test_benefit_cap_specified_benefits_properties.py,test_uc_statutory_pay_properties.py).LHA_allowed_bedrooms). Since Give sharers, boarders and lodgers their own rent, tenure and LHA category #2006, HB has its own (housing_benefit_LHA_allowed_bedrooms, reg 13D(3)), which gives a bedroom to a young person the UC count leaves out. So HB's category is compared with the reference, and with UC's, only where the two bedroom counts agree.test_examples_reach_the_casespins that the lone-parent example with a 19-year-old reaches that difference (HB category C). Separately, review found that main's UC count also leaves out the renter's own qualifying young person (UC Sch 4 para 10(1)(b)); that is Give benefit-unit members aged 16 or over a bedroom in the LHA size criteria #2008, which open PR Give benefit-unit members aged 16 or over a bedroom in the LHA size criteria #2010 fixes.test_benefit_cap_uc_and_hb_properties.py(1 test, 12 examples, each 1 to 8 families run with their HB and with none; not derandomised, so each run draws new examples): the reg 80(2A) and 75F(1)(g) invariants below.test_uc_single_claim_properties.py(Model a Universal Credit claim by a member of a couple as a single person (UC Regs 2013 reg 3(3)) #2084's structure kept; UC exceptions compared single vs stripped, HB variables single vs joint),housing_benefit/housing_benefit.yaml,universal_credit/uc_deductions.yaml,test_uc_deductions.pyandtest_abolish_benefit_cap_scenario.py(the scenario lifts both caps).e82c4acac: all 15 checks pass (gh pr checksexits 0), including Lint, the four smoke imports, the documentation builds, Fix evidence, andTest / YAMLand the fourTest / Pythonshards (run 38963800030), which run every pytest file above.e82c4acac:policyengine-core test policyengine_uk/tests/policy3,512 passed;test_benefit_cap_lha_scheme_split_properties.py7 passed;test_uc_single_claim_properties.py8 passed;test_housing_benefit_lha_order_properties.py3 passed;test_housing_benefit_pension_age_properties.py4 passed;test_abolish_benefit_cap_scenario.py1 passed;ruff format --check policyengine_ukclean (1,572 files).4cfc373c4(the same formulas; since then only documentation and the merge of Apply the Universal Credit Act 2025 standard allowance uplifts to 2029-30 #2242, which touches no file this PR changes):policyengine-core test policyengine_uk/tests/policy3,512 passed;test_benefit_cap_lha_scheme_split_properties.py7 passed;test_benefit_cap_uc_and_hb_properties.py1 passed;test_benefit_cap_specified_benefits_properties.py26 passed;ruff format --check policyengine_ukclean.LHA_capreading the UC rate; HB reduction ignoring the 50p minimum; UC shared-rate test ignoring reg 3(3); UC exception including WTC; HB cap reaching pension-age claims; HB shared-rate test ignoring the severe disability premium; UC cap rate reading responsibility under either scheme.ea46f7c3e: reverting either of its two formula changes fails both of its YAML cases (2 failed, 20 passed each time).Invariants
For every generated family and every example:
uc_benefit_cap_reduction= max(excess − childcare costs element, 0) on an award, else 0, where the excess counts HB as nil (reg 80(2A)).benefit_cap_reduction= UC + HB reductions.universal_credit/housing_benefitequal the award under the old shared cap.LHA_cap= min(rent,housing_benefit_LHA_rate). That rate equals the UC category'sBRMA_LHA_ratewherever the categories agree.test_benefit_cap_uc_and_hb_properties.py, both awards supplied):benefit_cap_welfare_benefitsat its amount before the cap (reg 75C(2)(b)).benefit_cap_reductionis its UC reduction; with HB, it is exempt from the HB cap.Reviews
Independent reviews through Subfleet, and reviews from Vahid Ahmadi and juaristi22:
claimants(); reading the LCWRA element diverged from main under a reform that sets it to nil; a stale doc). Fixed in 2391f94 (back to main's flag test) and b7e0b23.uc_benefit_cap_reductionname clash with Reconcile UC deduction and benefit cap components under the protected floor #1819; a family paid both; the hardcoded reg 82 threshold. Each is answered on the PR: findings 1 and 3 with their commits, 2 and 4 in writing.ea46f7c3eand the answers to Vahid's findings, with paired single-household probes on main and the head): APPROVE, three P3s, answered in documentation inab514f5b8.ab514f5b8and the merge of Apply the Universal Credit Act 2025 standard allowance uplifts to 2029-30 #2242): APPROVE, one P3 (approved training), answered ine82c4acac.Reviews of 85d9be9 and ea46f7c were cut short (a host shutdown and the six-hour limit); the 4cfc373 delta review covers both heads.
Coordination
270bfaabf; claimant and partner scopes, support-component ESA, the capped total) and Fix benefit-cap statutory-pay earnings exemption #2399 (85d9be9ff; the reg 82 earned-income measure).benefit_cap_earnings_exemption(£881 a month from April 2026, £10,572 a year). Its earnings change follows the move:git merge-treeof Pin benefit cap exemption rules with regression tests and legal references (#1818) #1820's head01e90fe28with this head puts the parameter intois_uc_benefit_cap_exempt_earnings.pywithout a conflict there. Pin benefit cap exemption rules with regression tests and legal references (#1818) #1820 does conflict inis_benefit_cap_exempt_health_disability.py, which this PR deletes, and in two property files; its exception fixes go into the per-scheme files.uc_benefit_cap_reduction). This PR keeps the name for the gross reg 81 amount. Reconcile UC deduction and benefit cap components under the protected floor #1819's floor-bounded amount should take another name (uc_benefit_cap_reduction_after_floorwas suggested on Reconcile UC deduction and benefit cap components under the protected floor #1819 on 10/02) and readuc_benefit_cap_reduction, notbenefit_cap_reduction. policyengine-core refuses a duplicate name at load, and the two PRs edit the same line ofuniversal_credit.py, so the clash cannot land silently.axiom:
uk/regulation/uksi/2013/376/80A(80A.test.yaml:single_not_greater_london_no_child_normal_home,single_not_greater_london_responsible_for_child_no_home);.../81(childcare costs element greater than excess so no reduction applies);.../schedule/4/paragraph/27and/28(renter_meets_all_specified_renter_conditions,renter_not_single_or_claiming_as_single).if eligibletowould_claimvariable descriptions #357. HB Sch 3 para 14: Survey structure, metadata and testing for other legacy benefits #386. HB regs 75A, 75C, 75D, 75E and 75F: Add semver actions #425.if eligibletowould_claimvariable descriptions #357 (reg 3(3) couple: single for UC, couple for HB), Add semver actions #425 (HB family with only a UC element; reg 75D(2) 50p minimum; reg 81 pipeline regressions), Survey structure, metadata and testing for Housing Benefit #384/Addif eligibletowould_claimvariable descriptions #357 (AFIP) and Survey structure, metadata and testing for personal benefits #389 (pension-age HB amounts; reg 60C).🤖 Generated with Claude Code
Reproducer:
policyengine_uk/tests/policy/baseline/finance/benefit/family/LHA_claimant_composition.yaml,policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/housing_benefit.yaml::Partially reduced benefit,policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/housing_benefit.yaml::Capped at 0,policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/housing_benefit_lha_category.yaml,policyengine_uk/tests/policy/baseline/finance/benefit/family/legacy_award_readers/passports.yaml::The claimant's own income-related ESA with the support component exempts the family from the benefit cap,policyengine_uk/tests/policy/baseline/finance/benefit/family/universal_credit/claimant_child_element.yaml::Case 1, an explicitly identified young claimant is not their own child.