Conversation
…ncome uc_earned_income subtracted benunit_tax, the whole benefit unit's income tax and NI on all income, from the unit's gross earnings. UC Regs 2013 reg. 55(5)(b) and reg. 57(2) step 3 deduct only tax and NI paid by the person in respect of their employment or trade. - uc_income_tax_on_earnings: income tax on the person's earnings, taken as the lowest slice of their non-savings income after their allowances (savings and dividends sit above it under ITA 2007 s. 16, property income above it in the engine and under s. 16A from 2027-28). - uc_national_insurance_on_earnings: Class 1 employee, Class 2, Class 4. - uc_individual_earned_income: gross earnings less the person's own pension contributions, tax and NI, floored at nil. - uc_earned_income: sum over the unit, less the work allowance. Fixes #1942. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- test_uc_earnings_deductions_properties.py: unearned income never changes earned income; UC is non-increasing in every kind of unearned income; the tax deducted equals the tax on earnings alone; earned income is never lower, and UC never higher, than under the pre-fix formula. - test_uc_state_pension_properties.py: the #1942 strict xfail now passes and loses its marker; pound-for-pound and the property-income equivalence cover families with earnings; a new strict xfail pins the Marriage Allowance transfer, which the model books on the recipient as the transferor's unused allowance (ITA 2007 s. 55B gives a fixed reduction). - Document the earnings deductions in the UC docs page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… at #1947 The docs edit left 'plus all of its unearned income' hanging off the earnings taper, which read as if unearned income were tapered. State the two deductions separately. The strict xfail's reason and the module docstring now cite #1947. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ldcare and local CTR Fixes #1986. - Benefit cap earnings exception (UC Regs 2013 reg 82): earned income is each person's earnings less their own tax, NI and pension contributions, summed over the unit, without the minimum income floor (reg 82(4)). The threshold is 16 hours a week at the national living wage, x 52 / 12, in whole pounds (reg 6(1A)(za)), x 12; GBP 430 a month before 1 April 2017. - Targeted childcare (SI 2014/2147 reg 1(3)(a)) and the Kingston, Merton, Newham and Westminster CTR schemes (Default Scheme para 37) read earned income before the work allowance, the new uc_earned_income_before_work_allowance, which uc_earned_income now uses. - uc_individual_earned_income_before_mif is copied unchanged from #1973 so the two PRs add identical files. - Adds the missing 2023-24 minimum wage rates (SI 2023/354). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…able pension contributions Review of #1949 found two defects in the new deductions. - uc_income_tax_on_earnings capped the tax on the earnings slice at the person's income_tax. When a tax reduction (the married couple's allowance) made that cap bind, the pension annual allowance charge and the High Income Child Benefit Charge raised the deduction, and so did more pension income. Reductions now come off the earnings slice first, as allowances do, so the deduction never includes a charge and does not move with other income. - uc_individual_earned_income deducted every pension contribution. Contributions paid after 75 are not relievable (Finance Act 2004 s. 188(3)(a)), so reg. 55(5)(a) does not deduct them. Adds YAML cases for both, draws a married couple's allowance in the property tests, and says in the test docstring that payroll giving (reg. 55(5)(c)) is not modelled. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…roperty tests The random generator rarely produced an earner old enough for the married couple's allowance, so the properties did not exercise tax reductions. A dedicated family shape now does. With it, restoring the old min(tax, income_tax) cap fails both the invariance and the differential property. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
uc_income_tax_on_earnings hard-coded savings, dividends and property as the incomes outside earned_taxable_income. A reform that adds another income to gov.hmrc.income_tax.earned_taxable_income_exclusions, such as one exempting pensions, then had that income subtracted twice, and the tax on earnings fell to nil. The formula now reads the list. Adds a YAML case with the reform as a parameter input. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…wn cell - The Class 3 and unearned income property now bumps one adult in every family by a realistic amount and mixes in earners just above the threshold, so it fails against the pre-#1986 formula (it did not before). - Adds a reg 82(4) property: switching every minimum income floor off never changes benefit cap earned income. - Moves the benefit cap earnings exception docs into a separate notebook cell, leaving the means-test cell that #1973 also edits untouched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…c-earned-income-consumers-1986
…income Follows #1949's f333e17: contributions paid after 75 are not relievable (Finance Act 2004 s. 188(3)(a)), so reg 55(5)(a) does not deduct them. uc_individual_earned_income_before_mif now matches uc_individual_earned_income apart from the minimum income floor. #1973 carries the same file without this change; whichever merges second takes this version. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Heads-up on an overlap: #2053 (fixes #2044) adds the same 1 April 2023 minimum wage rates as a standalone fix, cites the S.I. and regulation for every dated rate, and adds a pytest transcribed from the S.I.s. Once #2053 merges, this PR should drop its two 🤖 Generated with Claude Code |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Independent review of b696f8d (legal/code and tests/impact lanes): - The benefit cap is shared with Housing Benefit, so the UC earnings exception also excepted HB claimants; with the NLW-based threshold that newly excepted some in years when the threshold was under 10,152. Reg 82(1) applies "to an award of universal credit"; HB has its own exceptions (HB Regs 2006 regs 75E and 75F, WTC entitlement already in is_benefit_cap_exempt_health_disability). The income test is now uc_benefit_cap_earnings_threshold_met, and the exception needs a UC award before the cap as well. Adds the reviewer's HB regression. - Documents that the cap counts miscellaneous_income as the UC award does (FRS misc is mainly odd-job pay, reg 52(a)(iii)); the reg 66(1)(m) royalties split will move both together. - Tests: exact pins at 10,572 and 15,400, ages 74/75 for relievable contributions, a London BRMA in the counterexample, a floor-dependent childcare case, and a fixed 16,500 -> 16,501 childcare crossing in the monotonicity property (it kills a reversed-inequality mutant the random draws missed). Property 1 compares the income test, and the exception where there is a UC award both ways. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#2053 adds the same S.I. 2023/354 rates with regulation-level citations and tests, so #1999 no longer carries them and the two do not conflict. The benefit cap's 2023-24 threshold follows once #2053 merges (722 a month; 658 until then). The 2023 benefit cap cases move to 2024-25 (793 a month = 9,516 a year): the 9,520/9,500 pair and the Housing Benefit regression (9,600 earnings, cap 25,323). The property tests sample 2024 instead of 2023. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…iew's counterexamples - test_uc_unearned_benefits_properties.py (added on main by #1958) had a strict xfail pinned to #1942, which this fix turns into a pass. Remove it and widen the earnings-free invariants to all families, with Marriage Allowance off as in the State Pension file (#1947). - The tests review found that random draws missed two mutations. Pin its minimized counterexamples as @example cases: a pound of State Pension for a pensioner just above the personal allowance with an earning partner, and a pound of pension for an earner just above it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> # Conflicts: # policyengine_uk/tests/policy/baseline/finance/benefit/family/universal_credit/income/uc_earned_income.yaml # policyengine_uk/tests/test_uc_unearned_benefits_properties.py # policyengine_uk/variables/gov/dwp/universal_credit/income/uc_earned_income.py
… property fixtures #1896 presumes that a member under 20 who is at least 16 years younger than the claimant is the claimant's child. The State Pension and earnings property tests generate couples such as 67 and 18 without relationship inputs, so the presumption would read them as a parent and child and the tests would pass without exercising a couple (including the tests review's pinned 67-and-18 example). Set is_claimant_or_partner from each generated role, as #1896 did for main's fixtures. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…c-earned-income-consumers-1986 # Conflicts: # policyengine_uk/variables/gov/dwp/universal_credit/income/uc_earned_income.py
After #1896, is_claimant_or_partner is inferred when not given, and an adult under 20 who is 16+ years younger than the other can be presumed a child. The generated families have at most two adults, both claimants, as #1949's fixtures now declare. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Coordination with #2089 (each scheme its own benefit cap), stacked on #2084. #2089 moves the reg 82 earnings exception to Whichever lands second: put this PR's |
Summary
Three rules outside the Universal Credit award test a UC claimant's earned income, and each read the wrong figure. Fixes #1986.
is_benefit_cap_exempt_earnings). It took every member's employment and self-employment income less every member's income tax on all income and all NI, including voluntary Class 3. It deducted no pension contributions and compared the result with £10,152 a year hard-coded. It also excepted Housing Benefit awards, since HB shares the cap. Now it uses:benefit_cap_earned_income): each person's earnings less their own income tax and NI on those earnings and their relievable pension contributions, summed over the unit, without the minimum income floor (reg 82(4));benefit_cap_earnings_threshold): 16 hours a week at the national living wage, × 52 / 12, rounded down to whole pounds (reg 6(1A)(za)), × 12. That is £846 a month in 2025-26 and £881 in 2026-27, the figures GOV.UK publishes. It was £430 a month before 1 April 2017.uc_benefit_cap_earnings_threshold_met, and the exception also needs UC before the cap. HB awards keep their own exception (HB Regs reg 75E, Working Tax Credit entitlement), which the model already applies.uc_earned_income, which is after the work allowance, with the £15,400 limit. SI 2014/2147 defines earned income by UC Regs Part 6 Chapter 2, which comes before the work allowance. It now usesuc_earned_income_before_work_allowance.The model is missing the 2023-24 minimum wage rates (S.I. 2023/354), so 2023 uses 2022-23's. #2053 adds them. Until it merges, this threshold for 2023-24 is £658 a month instead of DWP's £722, and every other year is right.
The #1986 counterexamples, now pinned as YAML tests:
On the Enhanced FRS, in real runs of #1949's head against this branch, the change cuts 2026 UC by £18.3m. Six benefit-unit records (6.1k units) lose the earnings exception and are capped, and no unit gains. Both the earned income measure (chiefly pension contributions now deducted) and the 2026-27 threshold of £881 a month in place of £846 contribute. Two records with a child aged 2 lose the targeted childcare offer; the amount is withheld because it rests on two records. Housing Benefit and CTR amounts do not change.
Stacked on #1949 (which includes #1943 and main up to #1896). The PR targets
mainso CI runs, and its diff includes #1949's commits until it merges.Law (legislation.gov.uk
/data.xml, read 2026-10-01)UC Regs 2013 reg 82 (https://www.legislation.gov.uk/uksi/2013/376/regulation/82):
UC Regs 2013 reg 6(1A) (https://www.legislation.gov.uk/uksi/2013/376/regulation/6):
So 12.71 × 16 × 52 / 12 = 881.23 is £881. The issue's £10,574.72 a year leaves out this rounding.
Before 1 April 2017 reg 82(1)(a) read "is equal to or exceeds £430". S.I. 2017/138 reg 2(3)(a) substituted the hours formula from that date (https://www.legislation.gov.uk/uksi/2017/138/made).
National Minimum Wage Regulations 2015 reg 4 sets "the national living wage rate", the top age band of
gov.hmrc.minimum_wage.non_apprenticein every year since 2016 (point-in-time texts checked for each April from 2016 to 2026).The Local Authority (Duty to Secure Early Years Provision Free of Charge) Regulations 2014 (S.I. 2014/2147) reg 1 (https://www.legislation.gov.uk/uksi/2014/2147/regulation/1). An eligible child includes one whose parent is entitled to "universal credit where that parent had, in the relevant assessment period, earned income not exceeding the applicable amount", and:
Part 6 Chapter 2 is regs 52-64 (earned income, its deductions, and the minimum income floor). The work allowance is in reg 22, in Part 3 (awards).
Council Tax Reduction Schemes (Default Scheme) (England) Regulations 2012, Schedule para 37 (https://www.legislation.gov.uk/uksi/2012/2886/schedule/paragraph/37):
I re-read the four schemes the model cites:
None of the four subtracts a work allowance, which is a step in the award (reg 22(1)(b)), not in income.
Change
benefit_cap_earned_income(new, BenUnit): sumsuc_individual_earned_income_before_mif, each person's earnings less their own relievable pension contributions,uc_income_tax_on_earningsanduc_national_insurance_on_earnings, before the minimum income floor.uc_individual_earned_incomesince f333e17, it deducts only relievable contributions (none from 75, Finance Act 2004 s.188(3)(a)). Apply the UC minimum income floor to net earned income against a net threshold #1973's copy still deducts every contribution. Whichever of the two merges second should take this version.miscellaneous_incomeas earned, as the UC award does. In the FRS that is mainly odd-job pay (reg 52(a)(iii), "any other paid work"), but it also holds some reg 66(1)(m) unearned income such as royalties. The reg 66 work splits those out, and the cap test will follow because it shares this variable. The impact section bounds the choice.benefit_cap_earnings_threshold(new, BenUnit): 12 × (gov.dwp.universal_credit.benefit_cap.earnings_exception.monthly_amount+ floor(NLW ×weekly_hours× 52 / 12)).gov.hmrc.minimum_wage.non_apprentice, which equals the reg 4 rate in every year since 2016.uc_benefit_cap_earnings_threshold_met(new, BenUnit): earned income ≥ threshold.is_benefit_cap_exempt_earnings: the income test anduniversal_credit_pre_benefit_cap > 0. The award after the cap would be circular. The dead copy-pasted code is gone from this file. The same dead blocks remain inis_benefit_cap_exempt_health_disabilityand_other; Fix benefit cap exemption defects (#1818) #1820 removes them and Apply the benefit cap to mixed-age couples on Universal Credit, and keep them off pensioner Council Tax Reduction #1944 rewrites_other, so I left both alone.uc_earned_income_before_work_allowance(new, BenUnit): the sum ofuc_individual_earned_income, the UC Part 6 Chapter 2 figure (with the floor).uc_earned_incomenow subtracts the work allowance from it, so there is one sum.meets_universal_credit_criteria_for_targeted_childcare_entitlementandlegacy_council_tax_reductionreaduc_earned_income_before_work_allowance.Not modelled, as before:
Tests
YAML, hand-computed from the law (
benefit_cap_earnings_exception.yaml,meets_universal_credit_criteria_for_targeted_childcare_entitlement.yaml, additions tocouncil_tax_reduction.yamlandminimum_wage.yaml):uc_earned_incomenow inputuc_earned_income_before_work_allowance(same expected values).Property tests (
test_uc_earned_income_consumers_properties.py, Hypothesis, families of one or two adults with earnings, self-employment, pension contributions, Class 3 and four kinds of unearned income, in 2020, 2024, 2025 and 2026). Invariants:benefit_cap_earned_incomeand the income test unchanged, and the exception too wherever there is a UC award both ways. Families include earners just above the threshold.benefit_cap_earned_incomeequalsuc_earned_income_before_work_allowancewhere no floor applies and never exceeds it. Switching every floor off never changes it. The exception equals the income test and a UC award.council_tax_reductionequals the scheme formula recomputed from the model's own maximum, award and earned income.Mutation check: each mutant restores one piece of old behaviour, and all fail tests:
The tests reviewer also killed a mutant of each of the seven properties independently.
The first version of invariant 1 did not catch the old cap formula, because Hypothesis drew tiny bumps that crossed no threshold. Realistic bump sizes and near-threshold earners fixed that; it now fails against the old formula.
Local:
9709b9bc(this head, merged with Deduct only each person's own tax and NI on earnings from UC earned income #1949'sa57caf1dd): thegov/dwp,gov/dfe,gov/local_authoritiesandfinance/benefit/familyYAML passed 855 cases, and all 7 properties passed.uc_earned_income_before_work_allowanceandbenefit_cap_earned_income, so the award, the cap test, childcare and CTR count the same people.ce430940: the minimum wage files are back to Deduct only each person's own tax and NI on earnings from UC earned income #1949's, the 2023 cases are moved to 2024, and the benefit cap and minimum wage YAML passed 33 cases.b696f8d0,policyengine-core test policyengine_uk/tests/policypassed 1,433 cases.pyteston the new property file, Deduct only each person's own tax and NI on earnings from UC earned income #1949's and Count State Pension as Universal Credit unearned income #1943's property files,test_uc_deductions, the benefit cap scenario, the parameter descriptions and the fiscal-year tests gave 49 passed and 1 xfailed (the strict xfail pinning the Marriage Allowance deviation, Marriage Allowance is booked on the recipient as the transferor's unused allowance, not the fixed s.55B transfer #1947).4f9f8d8e, thegov/dwp,gov/dfe,gov/local_authorities,finance/benefit/familyand minimum wage YAML passed 679 cases, and all 7 properties passed.ruff format --checkis clean.Impact (Enhanced FRS, real runs)
Runs on a private copy of
enhanced_frs_2024_25.h5(sha256e433e532…), oneMicrosimulationper package state: #1949 ata57caf1dd(base, which includes main with #1896) against this branch at9709b9bc.salary_sacrifice_returned_to_income). The old formula counted that pay as earnings without deducting the contribution; reg 55(5)(a) deducts it. In units with UC before the cap, pension contributions go from £2.3bn in 2028 to £6.2bn in 2029.uc_earned_incomemoves by about 3p for some units, because the new intermediate sum is stored in float32.b8555a2d0, before Replace generic child and adult flags with each programme's legal definitions #1896): −£18.3m in 2026. On that base the 2 childcare records kept the offer through a legacy benefit.Scripts and outputs (aggregates only):
~/reviews/uc-earned-income-consumers-1986-2026-10-01/impact/(dataset_impact.py,compare_impact.py,childcare_mechanism.py,compare_v4_pr.json,childcare_mechanism_v4_2026.txt).Axiom
axiom: uk:regulations/uksi/2013/376/82 TheAxiomFoundation/rulespec-uk#399 queued. The module takes earned income excluding the floor (reg 82(4)) correctly. Its threshold leaves out the reg 6(1A)(za) whole-pound rounding (£881.23 against £881 in 2026-27), and no case can show it because every test uses a rate of £12.00. It is also undated: £430 before April 2017.axiom: uk:regulations/uksi/2015/621/4 TheAxiomFoundation/rulespec-uk#399 queued. Only the 2026-27 rate is encoded; Bump version #399 adds 2016-2025, including 2023-24's £10.42.axiom: uk:regulations/uksi/2014/2147/1 TheAxiomFoundation/rulespec-uk#400 queued. Not encoded.axiom: uk-{kingston-upon-thames,merton,newham,westminster}:policies/*/council-tax-reduction TheAxiomFoundation/rulespec-uk#401 queued. The modules take UC-award income as one opaque input; Stamp duty fixes #401 derives it from para 37 (earnings before the work allowance plus the award).axiom: uk:regulations/uksi/2006/213/75E TheAxiomFoundation/rulespec-uk#57 queued. The HB cap's own earnings exception (Working Tax Credit entitlement and the 39-week grace period) is not encoded. Since this PR stops applying UC reg 82 to HB, the extension on Metadata improvements and poverty gap additions #57 specifies reg 75E with companion cases, one matching the HB YAML case here.Each has the verbatim law, required outputs, a pasteable
review_findingand companion tests from the same ground truth as the YAML here.Review
Two independent Subfleet reviews of
b696f8d0both requested changes. Everything they raised is fixed in4f9f8d8eor answered here.Coordination
uc_individual_earned_income_before_mif. This PR adds the same file plus the relievable-contribution change above._before_mifadd/add conflict, which goes away if Apply the UC minimum income floor to net earned income against a net threshold #1973 takes this version (blob73a93702a), as noted on Apply the UC minimum income floor to net earned income against a net threshold #1973.is_benefit_cap_exempt_earningswithearned_income_taxand a hard-coded table of monthly thresholds. This PR replaces its defects 1 and 2:earned_income_taxstill includes tax on pensions;Fix benefit cap exemption defects (#1818) #1820 keeps AFIP and the dead-code removal in the other two files.
uc_earned_incomeand the cap exception to claimants. After this PR the restriction belongs inuc_earned_income_before_work_allowanceandbenefit_cap_earned_income.🤖 Generated with Claude Code