Give Universal Credit and Housing Benefit their own benefit cap and LHA shared-accommodation rules - #2089
Draft
MaxGhenis wants to merge 5 commits into
Draft
Give Universal Credit and Housing Benefit their own benefit cap and LHA shared-accommodation rules#2089MaxGhenis wants to merge 5 commits into
MaxGhenis wants to merge 5 commits into
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>
This was referenced Oct 2, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #2084 (UC reg 3(3) single claims; base branch
uc-reg3-3-single-claim). Review the commits after17b9b8a16; the head is 12ac785. GitHub retargets this PR tomainwhen #2084 merges.What was wrong
One set of variables served both Universal Credit and Housing Benefit although the two schemes' rules differ:
is_benefit_cap_single_claimant_rate/benefit_capused one "single claimant" test. 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_earningswere the union of both schemes' grounds:benefit_cap_reductionserved both, and applied neither UC reg 81 (the childcare costs element comes off) nor HB reg 75D(2) (the 50p weekly minimum stays).is_lha_shared_accommodation_rate_specified_renterset the one category both schemes read. UC Sch 4 paras 27-29 and HB reg 2(1) "young individual" with reg 13D(2)(a)(i) differ: UC has a single claim by a member of a couple and HB does not.#2084 gated the reg 3(3) consequences in these shared variables on
claims_legacy_benefitsas a stopgap. That stopgap 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.
Who is a single claimant
Exceptions
Reductions
Shared accommodation
So Housing Benefit's counterpart to UC's para 29(5) disability exception is the severe disability premium condition. In the model both lists come to the same benefits: attendance allowance, DLA care at the middle or highest rate, PIP daily living and AFIP. Para 14's carer condition (iii) is not observed.
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 QYPis_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) or_specified_benefit(reg 83: LCWRA and carer elements, a claimant's benefits; the reg 3(3) other member is not a claimant). No WTC, no age exception.is_housing_benefit_benefit_cap_exempt=_working_tax_credit(75E) or_specified_benefit(75F: the partner's benefits count) orhousing_benefit_pension_age_regulations_apply(reg 5). No earnings, LCWRA or carer-element exception.uc_benefit_cap_reduction: excess less the childcare costs element, on an award only (regs 78(1), 81)housing_benefit_benefit_cap_reduction: 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) without the stopgap; AFIP added per reg 2)housing_benefit_LHA_categorywithis_housing_benefit_young_individualandhousing_benefit_severe_disability_premium_applies(reg 13D(2)(a)(i), Sch 3 para 14)uc_LHA_cap(unchanged)LHA_capnow readshousing_benefit_LHA_rateOther changes:
benefit_cap_welfare_benefitsis the welfare benefits total. The model pays a family UC or HB, never both, so one total serves both schemes; a property test checks that no family has both. UC reg 80(2A), which counts HB as nil, and HB reg 75F(1)(g), which exempts a claimant receiving UC, therefore never bind.benefit_cap_reductionremains, as the sum of the two schemes' reductions. Downstream code reads it: uk-data's DWP benefit-cap calibration targets do. A family with neither award now has no reduction. In the Enhanced FRS no family had a reduction without an award, so the targets are unchanged.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.Converging with #2006/#2030. The LHA names come from #2006 so the two branches meet on the same files:
housing_benefit_LHA_category,housing_benefit_LHA_rate,is_housing_benefit_young_individual,housing_benefit_severe_disability_premium_applies, the parametergov.dwp.housing_benefit.severe_disability_premium.qualifying_benefits,lha_rate_for_categoryandcategory_maximum(..., category_variable). In #2006,LHA_categorystays the UC category. Where #2006 has more (the reg 13D(2)(a)(ii) route, sharers' rent, its own non-dependant tests), its versions supersede these. This PR keeps today's household-composition proxy (lha_renter_has_non_dependant) for both schemes. Both shared-rate tests still read responsibility under either scheme: a dependant under one scheme only is the other scheme's non-dependant, which the proxy does not identify. #2030 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 / reg 2(1) exceptions other than disability benefits, and Sch 3 para 14(2)(a)(iii).
Impact
Real Enhanced FRS runs, one at a time. Base is #2084's head 17b9b8a; branch is bd9a5a7, and no model code changed after it (
git diff bd9a5a76a HEAD -- policyengine_uk/{variables,parameters,utils}is empty). Private copy ofenhanced_frs_2024_25.h5, sha256 e433e532…. Weighted £m a year; records are survey records.benefit_cap_reductionwithout an award, so uk-data's cap targets are unchanged.LHA_capanduc_LHA_capare unchanged everywhere.Scripts and outputs:
impact/in the handover folder (dataset_impact.py, compare.py, r1/branch_vs_base.json).Tests
gov/dwp/benefit_cap_by_scheme.yaml(16 cases). Each scheme's exceptions:housing_benefit/housing_benefit_lha_category.yaml(9 cases):gov/dwp/benefit_cap.yaml(17). The reg 3(3) couple gets UC 14,753 and HB 22,020. The HB-only 19-year-old gives UC 14,753 and HB 22,020.LHA_claimant_composition.yaml(19). The reg 3(3) couple gets UC A and HB B.universal_credit/claims_as_single_person.yaml(27). 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. A legacy-claiming reg 3(3) family is single for UC and a couple for HB.test_benefit_cap_lha_scheme_split_properties.py, Hypothesis, derandomised, plus explicit examples of every scheme difference): differential tests against the parent commit's shared formulas. These are re-added verbatim underreference_names through a structuralReform, so one simulation computes old and new for the same families. 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): HB's cap rate, exceptions, young-individual test and category equal the joint claimants' whatever the reg 3(3) flag says.housing_benefit_LHA_rate.test_lha_uc_maximum.py,test_uc_deductions.pyandtest_abolish_benefit_cap_scenario.py(the scenario lifts both caps).policyengine-core test policyengine_uk/tests/policy: 1,781 passed.probes/mutate.py, run against a detached copy of the head). Each mutation was caught by the YAML files above, the split property file, or both:LHA_capreads the UC category's rate (properties);Invariants
For every generated family and every example:
uc_benefit_cap_reduction= max(excess − childcare costs element, 0) on an award, else 0.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, so it is a differential between the two lookup paths.test_examples_reach_the_caseschecks that each example changes the result it is there for: reg 3(3) under UC and legacy, reg 81, the HB-only young person, AFIP, the mixed-age couple on UC, an HB family with LCWRA, and reg 75D(2).Coordination
Comments posted on each related PR, with the port each needs:
uc-hb-split-on-2076, follows.uc_benefit_cap_reductionname.The landing job (launchd) waits for #2084 to merge, then retargets, merges main, tests, reviews the head and merges on gates.
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).🤖 Generated with Claude Code