Repository navigation
Count only claimants' income in Universal Credit - #1978
Conversation
uc_earned_income and uc_unearned_income summed every member of the benefit unit, so a dependent child's or qualifying young person's wages, profits, savings interest, dividends, rent or pension reduced the parents' award. WRA 2012 s. 8(4) and UC Regs 2013 reg. 22(1) deduct the income of the claimant, or the combined income of joint claimants. - is_uc_assessed_claimant: the single claimant or the two members of the couple whose income counts (is_uc_claimant, limited to the two eldest, as the reg. 62(3) couple rule already did). - uc_earned_income, uc_unearned_income: sum over the assessed claimants. - is_benefit_cap_exempt_earnings: reg. 82(1)(a) tests the claimant's or the couple's earned income, so a dependant's job no longer lifts the cap. - uc_childcare_work_condition: reg. 32(1) tests the claimant and the other member of the couple, not every member aged 18 or over. - add_for_members: the helper and its import are byte-identical to #1896's. Fixes #1976 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
YAML cases computed by hand from regs 22, 36, 80A and 82, and Hypothesis properties: a dependant's income never changes UC; earned and unearned income match the regulation's closed form; at most two assessed claimants; member order does not matter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…; stronger properties - uc_childcare_work_condition and uc_mif_applies read is_uc_assessed_claimant, so a third flagged member's work neither meets nor blocks the condition. - benefit_cap_reduction counts person-level benefits for the claimants only (WRA 2012 s. 96(1), reg. 80(1)). - Property tests build capped and childcare families, give dependants contributory benefits, flag every member as a claimant, and check earned and unearned income against the reg. 22 and reg. 72 figures. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eption threshold Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Coordination with #1999 (fixes #1986), which this PR will meet once both are on
A test merge of 🤖 Generated with Claude Code |
|
Coordination with #2076, stacked on #2027. #2076 rewrites
Before, a non-dependent adult's own award reduced the family's UC: with UC of £20,000 before the cap, a non-dependant's £5,000 of ESA cut UC from £14,753 to £9,753. Whichever lands second: keep #2076's claimant-or-partner lists alongside this PR's changes. |
|
Coordination with #2084 (UC claim by a member of a couple as a single person, UC Regs 2013 reg 3(3)). There, For this PR: Two more points from that PR's review:
|
Resolves conflicts with #1896 (claimant and partner), #1950 (no capital income in UC), #1949, #1973 and #2088 (reg. 32 exceptions): the income sums, the childcare work condition and the minimum income floor read is_uc_assessed_claimant; fixtures that relied on the old is_uc_claimant fallback flagging an adult child now supply the roles; the reg. 22 differential expects pensions plus tariff income, since savings interest is not reg. 66(1) income for anyone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Docs: drop the Marriage Allowance route, which #1896 closed. - Separate the lawful unearned-income case from contributory JSA/ESA supplied for a dependant, which reg. 5(5) rules out but the data hold. - Describe the two assessed claimants in the reg. 32 three-flag case. 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>
Hand-off to the UK hubHead: Checks: at Local runs: on the merged code, 2,418 YAML policy tests and the 17 Universal Credit property tests pass. Earlier, a mutation check killed all six mutants. Reviews: five independent reviews, kept in
Impact: real Enhanced FRS runs,
This is a law fix that moves aggregates, so it lands on the merge gates. There is no Max decision. Axiom: TheAxiomFoundation/rulespec-uk#397 ( Depends on: nothing open. #1973 has merged. Coordination: #1999, #2076 and #2084 each left a merge-order note on this PR. The PR body's "Overlap with open PRs" section gives the end state for each, whichever lands second. Dependants:
Follow-ups owed: none from this PR.
Worktrees:
|
|
Merged by the UK hub, which took this PR on handoff from local_5af4c464, under the PE-UK merge-on-gates rule.
|
…-3-single-claim #2081, #1973 and #1949 have merged, so main now carries this PR's base. Conflicts and their resolutions: - uc_individual_earned_income_before_mif.py: main's version (the age-75 pension contribution limit as #1949 landed it). uc_individual_earned_income.py and test_uc_earnings_deductions_properties.py merged cleanly and equal main's; so does test_uc_work_related_groups_properties.py, which now declares is_claimant_or_partner itself. - utils/uc_work_related_requirements.py: main's claimants() (it reads is_uc_assessed_claimant, which replaced couple_members() with the same formula), plus this PR's single-claim helpers. - uc_member_of_couple_claims_as_single_person.py and uc_is_ineligible_partner.py read is_uc_assessed_claimant instead of the removed couple_members(); no output changes. - is_uc_eligible.py: both docstrings' sentences. - uc_childcare_work_condition.py: #2088's reg 32 formula with this PR's reg 3(3) split, as posted on #2084: limb (a) for the s.40 claimant (is_uc_single_or_joint_claimant), limb (b) for every other member of the couple (is_uc_assessed_claimant), and reg 32(2) treatment only for a claimant. - is_benefit_cap_exempt_other.py merged without a conflict but lost `person = benunit.members`, which main removed and this PR's reg 83 line reads; restored. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fixes #1976
Summary
Universal Credit counted the income of the claimant's children and qualifying young people. Since #1896,
uc_earned_incomeanduc_unearned_incomesum over the claimant and partner and the programme's own children and young persons ("dropping dependants' own income is a follow-up"). So a dependant's wages, profits or pension still reduced the parents' award. This is that follow-up: the law counts the claimant's income only, or joint claimants' combined income.A 2026 example on
main: a lone parent aged 40 with no income, and a 17-year-old in upper secondary education.main£9,321.36 is 12 × (£424.90 + £351.88), the 2026-27 standard allowance and first-child element in the reg 36 table. 3,480 is the £12,000 less the £8,520 work allowance.
Two other rules read every member and are fixed the same way: the benefit cap earnings exception and the benefit cap total. The childcare work condition (#2088) already read the claimant and partner; it now also ignores a third member when inputs flag one.
The impact number needs reading with care. On the Enhanced FRS this raises 2026 UC by £4.98bn, and almost all of it comes from imputed incomes, not from what families told the survey:
See "Impact".
Law (legislation.gov.uk
/data.xml, read 2026-09-30)Welfare Reform Act 2012 s.8(3)-(4), on the amounts deducted from the maximum amount:
s.40: "“claimant” means a single claimant or each of joint claimants". s.2(1): a claim is made by "a single person" or "members of a couple jointly". So a claim has at most two claimants, and a child or qualifying young person is never one of them.
UC Regulations 2013 reg 22(1) deducts:
Reg 22(3) adds one person: where a member of a couple claims as a single person, the deduction is "the same as the amount that would be deducted ... if the couple were joint claimants". No provision brings a child's income in.
Reg 82(1)(a), the benefit cap earnings exception:
The cap itself applies to "the welfare benefits to which a single person or couple is entitled" (WRA 2012 s.96(1)), and reg 80(1) uses "the amount to which the single person or couple is entitled".
Reg 32(1), the childcare work condition:
Guidance. DWP's Advice for Decision Making says the same of income (E2191: "All of the claimant's unearned income ... should be deducted ... Where the claim is from joint claimants then the deduction is all of their combined unearned income"). It has no paragraph on a child's income, because nothing in the regulations brings it in. It is explicit on capital (H1077: capital owned by "a dependent child or qualifying young person is not to be included in the capital of the claimant").
Contrast with the older benefits. Income Support counted a child's income until 2004 (IS Regs 1987 regs 23 and 44), and Housing Benefit needed an express exclusion (HB Regs 2006 reg 25(3)). Universal Credit never counted it.
Change
is_uc_assessed_claimant(new): the single claimant or the two members of the couple whose income counts. It isis_uc_claimantlimited to the two eldest. Since Replace generic child and adult flags with each programme's legal definitions #1896is_uc_claimantflags at most two people unless inputs flag more; the limit is the rule Apply the UC minimum income floor to net earned income against a net threshold #1973's reg 62(3) couple threshold already used. The Act fixes the number of claimants; taking the eldest two of more than two flagged members (and the first entered on a tie in age) is a modelling rule for inputs that flag too many.uc_earned_income: sums the assessed claimants'uc_individual_earned_income, then takes off the work allowance.uc_unearned_income: sums the reg 66 list over the assessed claimants. Benefit-unit sources (uc_tariff_income) are added as they are.is_benefit_cap_exempt_earnings: sums the assessed claimants' earnings. Nothing else in that formula changes.benefit_cap_reduction: person-level benefits in the capped total (contributory JSA and ESA, Incapacity Benefit, Severe Disablement Allowance) count for the assessed claimants only.uc_childcare_work_condition(Apply the UC childcare work condition's partner exceptions and treated-as-working rules (UC Regs 2013 reg 32) #2088's reg 32 formula): tests the assessed claimants. With three flagged members, the youngest's work is no longer tested, consistent with their income not counting.uc_individual_earned_incomeanduc_mif_appliesnow readis_uc_assessed_claimantinstead of computing the same thing inline. No award changes.is_benefit_cap_exempt_earningsandbenefit_cap_reductionalso serve the Housing Benefit cap. Limiting them to the claimant and partner is right there too, provided the claimant and partner are flagged correctly. No Housing Benefit amount moves in the data.Overlap with open PRs
is_uc_benefit_cap_exempt_earningsand the capped total intobenefit_cap_welfare_benefits. Both still sum every member. Whichever of the two merges second must sum those overis_uc_assessed_claimant. Give Universal Credit and Housing Benefit their own benefit cap and LHA shared-accommodation rules #2089 also adds the reg 81(1)(b) childcare costs offset, whichmainlacks.is_benefit_cap_exempt_earningsto deduct tax on non-savings, non-dividend income (which, as it says, still includes tax on pensions) and pension contributions, and to use a dated threshold. It still sums every member; the combined end state is its formula summed over the assessed claimants.uc_earned_income_before_work_allowanceand the cap earnings test intobenefit_cap_earned_income. Whichever lands second appliesis_uc_assessed_claimantin those two variables (see the coordination comment above).benefit_cap_reductionwith explicit claimant-or-partner lists, covering means-tested awards as well as contributory benefits. That reaches the same end state as this PR's change to that variable and goes further, so if 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 lands second, keep its version.is_uc_assessed_claimantkeeps the partner of a member of a couple who claims as a single person, because their income counts as if the couple were joint claimants (reg 22(3)). Its docstring says so. If Model a Universal Credit claim by a member of a couple as a single person (UC Regs 2013 reg 3(3)) #2084 lands second, it applies its reading of reg 32(1) to the childcare formula: the s.40 claimant meets limb (a) and the other member limb (b). It also checks that itsclaims_as_single_person.yamlcases still pass.Tests
Run locally on the merged head: 2,418 YAML policy tests pass, and the 17 Universal Credit property tests pass (this PR's file and the two neighbouring UC property files). CI runs the full suite now that the PR targets
main.YAML tests, expectations computed by hand from regs 22, 36, 80A and 82 (derivations in the comments):
is_uc_assessed_claimant.yaml:income/uc_earned_income.yaml:income/uc_unearned_income.yaml:dependants_income.yaml:uc_childcare_work_condition_reg_32.yaml(Apply the UC childcare work condition's partner exceptions and treated-as-working rules (UC Regs 2013 reg 32) #2088's): the three-flagged-claimants case now expects the two eldest to be tested, as above, and a new case has the second eldest failing.Mutation check (before the main merge, on the same code). Each of six changes was undone in turn in a scratch copy, with the copy confirmed on the import path, and the tests run against it. Every mutant failed at least one test.
Invariants
The property tests (
test_uc_claimant_income_properties.py, Hypothesis) generate single claimants, couples and mixed-age couples, with up to four dependants aged 0 to 19 (in and out of education). Families have rent, childcare costs and capital, in England, Wales and Scotland, for 2020, 2026 and 2027. A third of them are built to be over the benefit cap, and a third to have working claimants paying for childcare.The same invariants hold on the whole Enhanced FRS. The impact scripts check them for every year from 2025 to 2030:
Impact (Enhanced FRS, real runs)
Runs.
mainat8090f1c19.06da1e693. Its only uncommitted changes were the two changelog fragments, committed after as0e74b27d6.enhanced_frs_2024_25.h5, sha256e433e532…), one realMicrosimulationper state.2026 UC goes from £78.2bn to £83.2bn, and the caseload from 6.40m to 6.60m benefit units. All 201k newly entitled units are in SPI-synthetic households.
Where it comes from (2026). Each benefit unit whose UC changes is assigned to the first source of dependant income it has, in the order below. This attributes each unit to one source; it does not separate the effects of several. The sources UC counts on
maincome first.Why children have earnings and benefits. The Enhanced FRS is the FRS plus a synthetic copy whose incomes are imputed from HMRC's Survey of Personal Incomes, and policyengine-uk-data#504 covers both of the following:
_reportedcolumns for the same people. 89 synthetic under-16 records have contributory ESA (none in FRS-origin households), £0.36bn among dependants in 2026.On
mainboth cut the parents' UC.The same real runs split by household origin (2026):
mainSo the part of this change that rests on what families reported is about £0.08bn a year for 61,000 benefit units. In 2026 that rests on 16 FRS households (15 in later years), each appearing twice in the dataset (the original and its capital-gains clone); the ten largest records account for 94% of it.
miscellaneous_incomeis built in policyengine-uk-data from odd-job income, allowances, royalties and the FRS child fieldschamternandchamttst.Sensitivity: under-16 earnings zeroed. The last column of the first table repeats both runs on a copy of the data with under-16
employment_incomeset to zero and nothing else changed (sha256b34ac1d7…). That change and the main-run change come from different groups, so the column is not an isolated effect of the data error:Benefit cap (2026). 189k benefit units (411 dataset records) no longer meet the earnings exception through a dependant's earnings, and the cap takes £0.21bn more. The two losing records are capped families who were exempt only because of a child's earnings. The change to the cap total moves nothing in the data: every benefit unit's cap reduction is the same with and without it.
Other programmes (2026).
Poverty (2026). AHC poverty falls 0.13 points and child AHC poverty 0.31 points (BHC: 0.03 and 0.09). With under-16 earnings zeroed the AHC falls are 0.07 and 0.15 points.
What this means for published numbers. The model bug and the data bug offset each other in UC:
main, setting under-16 earnings to zero raises 2026 UC from £78.2bn to £82.5bn.mainalso takes £63bn out of household net income and raises measured child AHC poverty from 23.9% to 29.1% (details in policyengine-uk-data#504). That is a sensitivity on the current weights, not a rebuilt dataset: other imputation fixes and recalibration were not run.universal_credit(targets/compute/benefits.py). I have not checked which model version built the current weights, or measured the fit to those targets before or after this change.Known gaps (follow-ups, not in this PR)
uc_carer_element, the LCWRA element and the limited-capability route to the work allowance read every member, so a dependant's caring or disability can add an element. Any member's contributory ESA, industrial injuries benefit or Armed Forces Compensation Scheme payment also exempts the benefit unit from the cap. For a lone parent aged 40 with children aged 5, 7 and 9 and a 17-year-old at school, in council housing in the North East at £20,000 rent, £1,000 of ESA or industrial injuries benefit for the 17-year-old lifts the capped 2026 UC from £17,821.00 to £40,263.20. Give the UC LCWRA and carer elements, the work allowance and the benefit cap exceptions on the claimants' circumstances only #1989, stacked on this PR, limits these exceptions to the claimants.main's cap reduction. Give Universal Credit and Housing Benefit their own benefit cap and LHA shared-accommodation rules #2089 adds it.is_uc_claimant(fromis_claimant_or_partner) is taken as a claimant whatever their age. Datasets that supply roles decide this; the calculator's fallback is Replace generic child and adult flags with each programme's legal definitions #1896's and Presume a much younger member is a flagged parent's child at any age #2040's.income/uc_unearned_income.yaml, the cap-total case independants_income.yaml), are qualifying young persons with contributory JSA or ESA, which reg 5(5) rules out. They test that supplied flags are respected; they are not lawful cases.Axiom parity
axiom: TheAxiomFoundation/rulespec-uk#397 queued
The Axiom modules for regs 22, 82, 32 and 81 already take claimant-scoped inputs, so no module's logic is wrong. For example,
uk/regulations/uksi/2013/376/22.yamlchooses between the claimant's and the joint claimants' income leaves, and nothing sums over members.encoded-correctis still not available, for four reasons read in the code:22.test.yaml,82.test.yamland32.test.yamlhave none).uk/programs/universal-credit/fy-2026-27.yaml) leaves reg 22's income leaves as runtime inputs, with onlyadult_of_benefit_unitandchild_of_benefit_unitrelations to fill them from.axiom_oracles/bridges/efrs_uk.py,project_universal_credit_income_deduction_inputs) fills reg 22's leaves from PolicyEngine'suc_earned_incomeanduc_unearned_income, then compares Axiom's outputs with the same two variables. That check passed with this bug in place, and will pass after the fix without testing it.rulespec-uk#397 and its two follow-up comments hold the dispatch-ready work:
review_finding.Signed encodes are billed to OpenAI, so dispatching them needs Max's approval.
Review
Three independent reviews ran before the main merge: two on the first version (code and tests; law and impact numbers) and a re-review of the fixes. The re-review found the two major findings resolved and asked for four minor changes, all made here:
A fourth review, of the merged head
0e74b27d6(GPT-6.1 Sol), found no blocker or major issue and approved with minor changes, made in2116a8314and in this description: the stale Marriage Allowance gap was removed, the ESA example was separated from the lawful cases, four roundings and the 16-household note were corrected, and the #1820 and childcare descriptions were tightened. A fifth, confirming review (Opus) found all six resolved and asked for further description fixes, then approved them, made in6284e91b1,b186ace32and here: the industrial injuries cap route is now disclosed beside ESA, and the remaining wording errors were corrected.🤖 Generated with Claude Code