Skip to content

Apply the UC minimum income floor to net earned income against a net threshold - #1973

Merged
MaxGhenis merged 11 commits into
mainfrom
uc-mif-net-floor
Oct 4, 2026
Merged

MaxGhenis merged 11 commits into
mainfrom
uc-mif-net-floor

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

The Universal Credit minimum income floor (MIF) compared the wrong things. uc_mif_capped_earned_income took max(gross earnings, gross floor), where the gross floor was the minimum wage × 35 hours × 52. uc_individual_earned_income then subtracted the tax and NI on the claimant's actual profits. So a self-employed claimant below the floor was treated as having the gross threshold less tax they never paid on it. For most of them (no tax or NI on small profits) that meant the whole gross threshold.

UC Regs 2013 reg 62 says something different:

  • it compares the claimant's earned income, which is already net of their own tax, NI and pension contributions (reg 55(5), reg 57(2));
  • it compares that with the reg 90(2) threshold "converted to net ... amounts by ... deducting such amount for income tax and national insurance contributions as the Secretary of State considers appropriate" (reg 62(4));
  • a claimant below it is "treated as having earned income equal to that threshold", the net amount (reg 62(2));
  • a member of a couple is lifted only while the couple's combined earned income is below the couple threshold. Any excess over that threshold comes off the floor (reg 62(3)). The model had no couple rule.

A 2026 example: a single claimant aged 30 with £5,000 of profits and council rent of £9,600.

  • Before: treated as earning £23,132.20, giving UC of £1,976.09.
  • After: treated as earning the net floor of £20,386.03 (£1,698.84 a month), giving UC of £3,486.48, which is £1,510.39 a year more.

On the Enhanced FRS this raises 2026 UC by £0.270bn. About 197,000 benefit units gain (151 records, a mean of £1,458 a year). About 3,600 lose (8 records), all with pension contributions. The UC caseload rises by about 2,300.

Builds on #1949 (per-person tax on earnings, which fixes #1942) and #1943, both now merged into main.

Law (legislation.gov.uk, read 2026-09-30 from /data.xml)

UC Regs 2013 reg 62 (https://www.legislation.gov.uk/uksi/2013/376/regulation/62):

(2) Where this regulation applies to a single claimant, for any assessment period in respect of which the claimant's earned income is less than their individual threshold, the claimant is to be treated as having earned income equal to that threshold.

(3) Where this regulation applies to a claimant who is a member of a couple, for any assessment period in respect of which— (a) the claimant's earned income is less than their individual threshold; and (b) the couple's combined earned income is less than the couple threshold, the claimant is to be treated as having earned income equal to their individual threshold minus any amount by which that amount of earned income combined with their partner's earned income would exceed the couple threshold.

(4) In this regulation, references to the claimant's individual threshold and to the couple threshold are to the amounts set out in regulation 90(2) and 90(3) respectively, converted to net ... amounts by— (a) . . . (b) deducting such amount for income tax and national insurance contributions as the Secretary of State considers appropriate.

Reg 90(2) (https://www.legislation.gov.uk/uksi/2013/376/regulation/90):

A claimant's individual threshold is the amount that a person of the same age as the claimant would be paid at the hourly rate applicable under regulation 4 or regulation 4A(1)(a) to (c) of the National Minimum Wage Regulations for— ... (b) the expected number of hours per week in the case of a claimant who would otherwise fall within section 22 of the Act ..., converted to a monthly amount by multiplying by 52 and dividing by 12.

Reg 90(3)(a) makes the couple threshold for joint claimants "the sum of their individual thresholds". The rate is the one for the person's age: reg 4A(1)(d), the apprenticeship rate, is not in the list.

The Secretary of State's deduction (the modelling choice)

Reg 62(4)(b) leaves the tax and NI deduction to the Secretary of State. The model deducts what a self-employed person would pay if the threshold were their only income:

  • income tax on the threshold less the standard personal allowance, at the person's own rest-of-UK or Scottish rates;
  • Class 2 and Class 4 NI on profits equal to the threshold. Class 2 is nil from April 2024, so in 2026 this is Class 4 at 6% above £12,570. As for the person's actual contributions, Class 2 stops at State Pension age, and Class 4 is not due from anyone over it at the start of the tax year (SI 2001/1004 reg 91(a)): someone who reaches it during the year still has Class 4 deducted for that year.

This is DWP's own method, on the evidence:

  • DWP's guidance "Applying the Minimum Income Floor", version 9 (3 April 2017, deposited in Parliament as DEP2017-0556), step 4: "Taking off the Income Tax and Class 2 and Class 4 NI contributions payable on actual earnings at that level, to get an assumed net monthly income - this is the claimant's MIF." Later versions say "appropriate NI contributions" (v12, 2018) and "Notional tax and National Insurance payable on actual earnings" (v16 to v23, 2021 to 2025). None names Class 1.

  • Figures DWP issued or applied match this basis. Each row below is the minimum wage × 35 × 52 / 12, less income tax and NI, computed monthly at that year's statutory rates with no rounding of the threshold. The last two columns show the alternatives.

    Source Year Floor Self-employed NI Class 1 Whole-pound threshold
    Griffiths and Wood, Going it alone, University of Bath IPR, July 2025, note 3: "if the gross individual monthly earnings threshold is £1851.85, the net MIF would be £1,642.72 (information supplied by the DWP)" 2025-26 £1,642.72 £1,642.72 £1,626.63 £1,642.09
    Claimant, MoneySavingExpert, 25 Nov 2019: "The minimum income floor was set at £1144.15 a month" 2019-20 £1,144.15 £1,144.15 £1,141.34 £1,144.02
    ADM H4079 (Kyle), illustrative, in whole pounds: £1,016 less £70 2015-16 £946 £946.46 £948.30

    A May 2024 thread agrees. DWP told the claimant "£1556", which fits self-employed NI (£1,556.30) and not Class 1 (£1,542.59). The pence there came from another forum user, so it is a consistency check only.

  • The 2013 original text of reg 62 made the deduction "an amount that the Secretary of State considers appropriate to take account of any income tax or national insurance contributions for which the person would be liable in respect of the assessment period if they had earned income of that amount" (https://www.legislation.gov.uk/uksi/2013/376/regulation/62/2013-04-29). It was discretionary then too, but tied to tax on the threshold itself, not on actual profits.

The other reading is employee NI. DWP's self-employment quick guide describes the floor as "the amount of money an employed person in a similar situation to you would earn on the National Living Wage or National Minimum Wage, after tax and National Insurance". LITRG's illustrative example ("say £225.07" for 2025-26) uses Class 1. The parameter gov.dwp.universal_credit.means_test.minimum_income_floor.self_employed_national_insurance (default true) switches to primary Class 1 when set to false. A real run with it set to false raises 2026 UC by £0.294bn, against £0.270bn by default.

No whole-pound rounding. Reg 6(1A)(a) disregards "a fraction of a pound" in amounts calculated "for the purposes of ... regulation 90", the conditionality earnings threshold. The floor is calculated for reg 62. The two pence-level DWP figures above come from the unrounded thresholds (£1,851.85 and £1,245.18), and rounding down first would give £1,642.09 and £1,144.02. The ADM's illustrative example rounds to whole pounds (£1,016 less £70). Reg 62(4)'s reference to "the amounts set out in regulation 90(2)" could be read either way; the model follows DWP's figures.

Change

  • uc_minimum_income_floor_gross (new): the minimum wage for the person's age (never the apprenticeship rate) × expected hours × 52.
  • uc_minimum_income_floor_income_tax, uc_minimum_income_floor_national_insurance (new): the notional deductions above.
  • uc_minimum_income_floor: now the net floor, gross less both deductions.
  • uc_individual_earned_income_before_mif (new): actual earned income. That is earnings less the person's own relievable pension contributions (none from age 75, Finance Act 2004 s.188(3)(a)) and their own income tax and NI on those earnings. A trading loss counts as nil self-employed earnings; reg 57(2) does not set it against employed earnings. Deduct only each person's own tax and NI on earnings from UC earned income #1949 put this in uc_individual_earned_income.
  • uc_individual_earned_income: applies reg 62(2) and (3).
    • The couple threshold is the sum of the couple's net floors. The partner's earned income is their actual earned income.
    • When both partners are under their floors, each is treated as having their own floor, whichever is applied first.
    • For a single claimant, reg 62(3) reduces to reg 62(2).
    • A claim has at most two claimants, and is_uc_claimant (now is_claimant_or_partner) flags at most two. Where inputs flag more, the two eldest are the couple.
  • uc_mif_applies: now claimants only (reg 62 applies to "a claimant"), and a trading loss counts. Gainful self-employment is a trade carried on "in expectation of profit" (reg 64), and ADM H4503 applies the floor in a loss-making period.
  • uc_mif_capped_earned_income: removed. Nothing else in this repo, policyengine-uk-data, policyengine.py or policyengine-api uses it.
  • Deduct only each person's own tax and NI on earnings from UC earned income #1949's invariant 4 (test_fix_only_removes_deductions) compared against the pre-UC earned income deducts the whole benefit unit's tax, including tax on pensions and other unearned income #1942 formula, which used uc_mif_capped_earned_income. It now runs with everyone in a start-up period, because the net floor moves earned income in either direction.
  • The docs page on Universal Credit describes the floor.

Known gaps (follow-ups, not in this PR)

  • Reg 62(1)(b). The floor applies only to a claimant who "would, apart from this regulation or regulation 90, fall within section 22" (all work-related requirements). The model still applies it to everyone with self-employment income outside a start-up period. That includes claimants with limited capability for work-related activity, carers, responsible carers of a child under 3, claimants within 11 weeks before their expected week of confinement or within 15 weeks after the date of confinement (reg 89(1)(c)), and the older partner of a mixed-age couple, who has reached the qualifying age for Pension Credit (reg 89(1)(a)). Apply the UC minimum income floor only to claimants subject to all work-related requirements #2081, stacked on this PR, applies reg 62(1)(b). In the 2026 run, of the 200,000 people in UC benefit units whom the floor lifts: about 43,800 are in a benefit unit whose youngest child is under 3 (counting both partners), 6,800 have limited capability for work-related activity, 5,300 are carers, and none has reached State Pension age.
  • Reg 88(2) expected hours. The model uses 35 hours for everyone. DWP says self-employed parents of children aged 3 to 12 "typically have their Minimum Income Floor set using a maximum of 30 hours per week" (written answer 129349, 28 April 2026).
  • Reg 90(2)(a) and (3)(b). A partner in the work-focused-interview or work-preparation group has a 16-hour threshold. A claimant whose partner is not a joint claimant uses a 35-hour partner amount. Neither is modelled.
  • Data. The Enhanced FRS never sets uc_is_in_startup_period and has no gainful self-employment test (reg 64). So every self-employed claimant in a UC benefit unit is treated as subject to the floor: 309,000 people in 2026.
  • Dependants' earnings. uc_earned_income sums the claimant and partner and the benefit unit's UC children and qualifying young persons, so a dependent qualifying young person's earnings count towards the claimants' UC. That predates this PR.
  • Break-even. With no self-employment status input, the model reads zero profit as no self-employment. So a loss gets the floor (reg 57(2), ADM H4503) and exactly £0 does not. For example, in 2026 a single claimant with council rent of £9,600 gets UC of £3,486.48 at −£1 and £14,698.80 at £0. In law a break-even trader in gainful self-employment keeps the floor. The Enhanced FRS has no negative profits, so the impact is unaffected.
  • Annual assessment. Reg 62 applies in each monthly assessment period. The model works on annual amounts, so a claimant whose profits fluctuate is floored on their annual average, not in each low month. This holds across the whole UC model.
  • Parameter gaps. The model has no 2016-17 personal allowance, so the 2016 floor uses the 2015-16 one. This predates this PR.

Tests

YAML tests are hand-computed from the law at the rates the model holds, in income_floor/uc_minimum_income_floor.yaml, income_floor/uc_mif_earned_income.yaml and income_floor/uc_MIF_applies.yaml. They cover:

  • the gross threshold, including an apprentice (age rate, not the apprenticeship rate);
  • the net floor for England, Scotland, age 19 (18 to 20 rate), over State Pension age, reaching State Pension age after 6 April (Class 4 still deducted), and 2020 (Class 2 and Class 4);
  • a single claimant below the floor, with the UC award, and UC staying flat as profits rise under the floor. At £20,000 of profits it is £3,486.48, the same as at £5,000; before this PR it was £3,038.58 against £1,976.09;
  • the floor applying above the gross threshold because pension contributions take net earnings under it;
  • the floor not applying when net earnings are above it, even below the gross threshold (low expenses, so the claimant takes the trading allowance and pays less tax and Class 4 than the floor deducts);
  • start-up period, no self-employment, dependant, a trading loss, a trading loss alongside a job, and break-even;
  • ADM H4080 examples 1 and 2 (the husband is treated as having £700 a month), both partners under their floors, the couple at the threshold;
  • a couple built from gross incomes, where the partner's excess over their floor reduces the floor, with the UC award;
  • a third adult flagged as a claimant, who does not join the couple threshold.

Property tests (test_uc_minimum_income_floor_properties.py, Hypothesis) run over generated populations of single people, couples, couples with an older partner aged 65 to 80 (mixed-age once past State Pension age) and couples with an adult child in their benefit unit, in England, Wales and Scotland, in 2020, 2026 and 2027. The notional NI differential also always runs a 66-year-old in 2026, who reaches State Pension age after 6 April, under both NI bases. Each invariant below holds for every input.

Invariants

  1. The floor never lowers earned income. It changes it only for claimants it applies to.
  2. The floor holds.
    • A single claimant it applies to has at least the net floor.
    • A member of a couple it applies to leaves the couple with at least min(couple threshold, their own floor + partner's earned income).
    • No one is lifted above their own floor.
  3. The couple threshold caps the top-up. Whenever the floor lifts anyone, the couple's combined earned income is at most the couple threshold.
  4. Differential against a closed form. The model's reg 62(2)/(3) conditions equal max(E, T − max(0, T + E_partner − T_couple)), written in the test from the regulation. The two forms agree because the couple threshold is the sum of the individual thresholds.
  5. Differential against the tax engine, under both NI bases.
    • The notional income tax equals the income_tax of the same person paid the gross threshold as their only income.
    • The notional NI equals their ni_class_2 + ni_class_4 with profits of that amount (default basis), or their ni_class_1_employee on pay of that amount (parameter switched).
    • So the net floor is never above the gross threshold.
  6. Monotone. More earnings for any adult never lower the benefit unit's uc_earned_income and never raise UC before the benefit cap. The property draws profits from −£10,000 to £40,000. The one intended exception is a loss raised to exactly £0, because the model reads zero profit as no self-employment (see known gaps). Before this PR, UC rose with the profits of a self-employed claimant under the floor: profits of £20,000 gave £715 more UC than £15,000 in 2026, because more tax on actual profits came off the gross threshold.

Marriage Allowance is off in the property tests. A transfer can lower one partner's earned income when the other's earnings rise, which is lawful and not part of this change.

Impact (Enhanced FRS, real runs)

Base: main at be877c81c (2.115.0, which includes #1949 and #1943). Branch: c711defaa, this PR merged with that main (later commits change only tests). No run had uncommitted tracked changes. All three use a copy of the Enhanced FRS 2024-25 (enhanced_frs_2024_25.h5, sha256 e433e532…), one real Microsimulation per state. The Class 1 column is a separate real run with the parameter set to false. Benefit units are counted in thousands, with records in brackets. Poverty is in percentage points.

Year UC change UC change, Class 1 basis Units gaining Units losing UC caseload AHC poverty AHC child poverty
2025 +£0.243bn +£0.267bn 208k (153) 3.6k (8) +1.9k -0.030 -0.069
2026 +£0.270bn +£0.294bn 197k (151) 3.6k (8) +2.3k -0.020 -0.042
2027 +£0.267bn +£0.290bn 196k (152) 3.6k (8) +0.9k -0.105 -0.271
2028 +£0.263bn +£0.286bn 188k (146) 5.4k (9) +1.1k -0.082 -0.221
2029 +£0.190bn +£0.214bn 173k (136) 24.4k (25) +0.2k -0.061 -0.173
2030 +£0.189bn +£0.212bn 174k (140) 22.5k (23) +1.2k -0.109 -0.280

How 2026 decomposes, for people in UC benefit units:

  • Floored before and after: 200k people. They are now treated as having the net floor, not the gross threshold less the tax on their actual profits. Their earned income falls by £0.474bn.
  • Floored before, not after: 3.8k people. All are below their own net floor, but their partner's earnings take the couple to the couple threshold, so reg 62(3) gives them no top-up. The old gross floor had no couple rule. Earned income falls by £0.037bn.
  • Floored after, not before: 1.0k people (2 records). Their pension contributions exceed their earnings. The old floor raised their gross earnings to the gross threshold, and the contributions then took their earned income to nil; now their nil net earnings are below the net floor, which they are treated as having. Earned income rises by £0.020bn.
  • Reg 62(3): 9.2k people. Their partner's earnings above the partner's own floor reduce their floor. This is included in the lines above.
  • Losers (8 records in 2026, 23-25 records a year from 2029). In every year, every losing benefit unit has a member who makes pension contributions and whose earned income rose. Reg 55(5) and reg 57(2) take relievable pension contributions off earned income before the comparison, so their net earnings fall below the net floor. The old floor was compared with gross earnings and the contributions came off afterwards, so it either missed them (gross earnings above the gross threshold) or left them below the net floor. The count rises in 2029 because the model then caps salary-sacrifice pension contributions at £2,000 and treats the excess as ordinary contributions (total contributions go from £55.8bn in 2028 to £72.1bn in 2029), which come off UC earned income. In 2029, 19 of the 25 losing records (20.9k of 24.4k units) have a self-employed member with no pay in 2028 who from 2029 has pay, and pension contributions raised by the same amount: the model adds salary sacrifice above the cap to both (salary_sacrifice_returned_to_income). So most 2029 losers are people to whom the data give salary sacrifice but no pay.
  • Dependants. The floor no longer applies to 42 records of dependants with self-employment income. None is in a UC benefit unit.

Every data invariant holds in every year: the floor never lowers anyone's earned income, leaves everyone it doesn't apply to unchanged, and never lifts anyone above their own floor.

Earlier runs, before #1949 merged, gave +£0.281bn for 2026 with base c98c53c58 and branch ae8f59fd1 (impact/run2-base-c98c53c58); +£0.281bn for 2026 with base d0fc22f39 and branch ee16391c4 (impact/run1-base-d0fc22f39).

Axiom parity

axiom: uk:regulations/uksi/2013/376/62 encoded-correct (rulespec-uk uk/regulations/uksi/2013/376/62.test.yaml: single_claimant_below_individual_threshold_is_deemed_to_threshold, couple_claimant_uses_surplus_allocation_with_lowest_combined_income); composed UC pipeline couple floor TheAxiomFoundation/rulespec-uk#396 queued

The reg 62 module passes all 13 law-derived cases in the issue, including this PR's net floor and couple cases (its deduction is a leaf). The composed UC pipeline applies one floor to the couple's combined earnings, so it fails 4 of 9 couple cases. Example: a self-employed claimant on £400 a month with a partner on £1,000 is deemed £927.68 a month too high. rulespec-uk#396 has the dispatch-ready re-encode (review_finding, companion tests from the same figures as these YAML tests). Signed encodes are OpenAI-billed, so dispatch is Max's call.

🤖 Generated with Claude Code

MaxGhenis and others added 3 commits September 30, 2026 16:39
…threshold

UC Regs 2013 reg 62 compares a self-employed claimant's earned income,
after their own tax, NI and pension contributions, with the reg 90(2)
individual threshold "converted to net ... amounts by ... deducting such
amount for income tax and national insurance contributions as the
Secretary of State considers appropriate" (reg 62(4)), and treats them as
having that net amount. The model took max(gross earnings, gross floor)
and then subtracted the tax and NI on the claimant's actual profits, so a
claimant under the floor was treated as having the gross threshold less
the tax on their actual profits.

- uc_minimum_income_floor_gross: minimum wage x expected hours x 52 / 12,
  rounded down to whole pounds (reg 6(1A)(a)), times 12.
- uc_minimum_income_floor_income_tax / _national_insurance: the notional
  income tax and primary Class 1 NI on the threshold as the person's only
  pay (the modelling choice for the Secretary of State's discretion; a
  parameter switches to Class 2 and Class 4).
- uc_minimum_income_floor: the net floor.
- uc_individual_earned_income_before_mif: actual earned income after the
  reg 55(5) / 57(2) deductions.
- uc_individual_earned_income: reg 62(2) for single claimants and reg
  62(3) for couples (the couple threshold is the sum of the claimants'
  floors).
- uc_mif_applies: claimants only.
- uc_mif_capped_earned_income is removed.

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

- The notional NI now defaults to Class 2 and Class 4 on profits equal to
  the threshold. DWP's 2017 guidance on applying the floor says so, and the
  floors DWP has given claimants match it to the penny (1,144.15 a month in
  2019-20, 1,556.30 in 2024-25); the parameter switches to primary Class 1.
- The threshold keeps its pence: reg 6(1A)(a) rounds amounts calculated for
  reg 90 itself, and DWP's floors are unrounded.
- The threshold uses the minimum wage for the person's age, never the
  apprenticeship rate (reg 90(2) names NMW Regs reg 4 and 4A(1)(a)-(c)).
- A trading loss counts as self-employment for the floor (reg 64, ADM
  H4503) and is not set against employed earnings (reg 57(2)).
- The couple is at most the two eldest claimants, so an adult child
  flagged as a claimant does not join the couple threshold.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The no-rounding evidence is the net floor of 1,642.72 a month that DWP
  supplied for 2025-26 on a threshold of 1,851.85 (University of Bath IPR,
  "Going it alone", 2025), and the floor set on a claimant's award at
  1,144.15 a month in 2019-20. The 1,556.30 figure for 2024-25 came from a
  forum user, not DWP, so it no longer appears as DWP's.
- Property tests now draw trading losses. Monotonicity excludes the one
  intended exception, a loss raised to exactly zero, which the model reads
  as no self-employment; a YAML test pins that edge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 2 commits October 1, 2026 10:35
The generated populations now include a couple with an adult child the
model also flags as a claimant, and the test reference takes the couple as
the two eldest claimants, as the model does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…c-mif-net-floor

# Conflicts:
#	docs/book/programs/gov/dwp/universal-credit.ipynb
…c-mif-net-floor

# Conflicts:
#	docs/book/programs/gov/dwp/universal-credit.ipynb
@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Formula changes in #1949, which this PR stacks on. Head b8555a2: three added commits on c98c53c, no history rewrite.

  1. uc_income_tax_on_earnings (f333e17). The final min_(tax, income_tax) cap is now max_(0, tax - reductions), with reductions = add(person, period, gov.hmrc.income_tax.income_tax_subtractions). Tax reductions (married couple's allowance, other tax credits) now come off the tax on earnings first. With the old cap, the pension annual allowance charge and HICBC leaked into the deduction whenever MCA made the cap bind.
  2. uc_income_tax_on_earnings (b8555a2). The incomes outside earned_taxable_income are read from gov.hmrc.income_tax.earned_taxable_income_exclusions, intersected with adjusted_net_income_components, not hard-coded. A reform exempting pensions no longer subtracts them twice.
  3. uc_individual_earned_income (f333e17). pension_contributions are deducted only below gov.hmrc.pensions.pension_contributions_relief_age_limit (75), per Finance Act 2004 s.188(3)(a).

uc_national_insurance_on_earnings is unchanged. On #1949's tree: YAML policy suite 1,394 passed; both property files 9 passed, 1 xfailed.

Change 3 is in uc_individual_earned_income, which this PR's floor wraps, so expect a conflict there when merging #1949's head. The post-merge launchd job (com.maxghenis.pe-uk-1973-after-1949) should not merge this PR until that conflict is resolved and the floor tests are re-run.

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Coordination with #1999 (fixes #1986: benefit cap earnings exception, targeted childcare, local CTR).

#1999 needs earned income without the floor for reg 82(4), so it adds this PR's uc_individual_earned_income_before_mif, copied from ae8f59fd1, with one change. Since #1949's f333e17, uc_individual_earned_income deducts only relievable pension contributions: none after 75 (Finance Act 2004 s.188(3)(a)). #1999's copy does the same:

        # Contributions paid after the person reaches 75 are not relievable
        # (Finance Act 2004 s. 188(3)(a)), so reg. 55(5)(a) does not deduct
        # them.
        age_limit = parameters(
            period
        ).gov.hmrc.pensions.pension_contributions_relief_age_limit
        relievable_pension_contributions = person("pension_contributions", period) * (
            person("age", period) < age_limit
        )
        tax_and_national_insurance = add(
            person,
            period,
            ["uc_income_tax_on_earnings", "uc_national_insurance_on_earnings"],
        )
        return max_(
            0, earnings - relievable_pension_contributions - tax_and_national_insurance
        )

It also adds the FA 2004 s.188 reference. This PR has not merged #1949's b8555a2d0 yet. When it does, uc_individual_earned_income.py and test_uc_earnings_deductions_properties.py conflict with #1949, not with #1999, and the relievable rule has to move into _before_mif anyway. If the file then matches #1999's byte for byte (blob 73a93702a at b696f8d01), the two PRs merge in either order. Otherwise whichever merges second takes one version.

🤖 Generated with Claude Code

MaxGhenis and others added 5 commits October 4, 2026 09:47
Brings the branch up to main at be877c8, which includes #1949
(fc1ecc4) and #1943.

Conflicts:
- docs/book/programs/gov/dwp/universal-credit.ipynb: main's notebook
  with this PR's minimum income floor paragraph re-inserted after the
  earnings-deductions sentence.
- uc_individual_earned_income.py: this PR's reg 62(2)/(3) floor. Main's
  Finance Act 2004 s.188(3)(a) age filter on pension contributions is
  ported to uc_individual_earned_income_before_mif, where this PR takes
  the deductions; the file is copied as is from #1999 (blob 73a9370)
  so the two PRs merge in either order.
- test_uc_earnings_deductions_properties.py: main's file with this PR's
  start-up-period note, the pre-#1942 gross earnings and invariant 4's
  start-up setting.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main now gives no trading allowance on a profit above 1,000 when gross
receipts are unknown (#1881), so the YAML expectations that took 1,000
off taxable profit are recomputed by hand: tax on 20,000, 22,000 and
24,000 (less 3,000 pension) of profit, and the earned income that
follows. The "before this fix" figures are main's own (be877c8),
from a real run of those households.

Without the allowance, this claimant's tax and Class 4 are the ones
the net floor deducts, so a profit below the gross threshold always
leaves them below the net floor. The case showing the floor does not
apply above the net floor, though below the gross threshold, now has
gross receipts of 23,200 on a profit of 23,000: with 200 of expenses
the trading allowance (ITTOIA 2005 s. 783AI) gives a taxable profit
of 22,200.

is_uc_claimant now follows is_claimant_or_partner, which flags at
most two people, so the third-claimant case flags all three by input,
and the comments no longer say the model flags an adult child.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main (#1907) split Class 4 out of ni_liable into ni_class_4_liable:
Class 4 is due for the whole tax year from anyone not over State
Pension age on 6 April (SI 2001/1004 reg. 91(a)). The floor's notional
NI still multiplied Class 4 by ni_liable, so a claimant who reaches
State Pension age between 7 April and 6 October paid Class 4 on their
actual profits but had none deducted from the threshold. In 2026 that
is everyone aged 66 with the default birthday: notional NI 0 against
633.73, a floor 633.73 too high.

Class 1 and Class 2 keep ni_liable; Class 4 uses ni_class_4_liable,
matching the model's actual contributions. An exhaustive check over
ages 16-80, birthday months 0-11, 2020, 2026 and 2027 and both NI bases
finds no difference from ni_class_2 + ni_class_4 or ni_class_1_employee
on the threshold.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The notional NI invariant now covers people who reach State Pension age
during the tax year, for whom Class 4 stays due (SI 2001/1004 reg.
91(a)) while primary Class 1 and Class 2 stop. Ages 65 and 66 were
never drawn, so the Class 4 liability mismatch fixed in the previous
commit went unseen.

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

The generated draws reach a 66-year-old in 2026 only by chance, so the
notional NI differential gets two explicit examples: that person, under
both NI bases. On the previous formula the self-employed example fails
by the 633.73 of Class 4. The docstring now says the older-partner
shape starts at 65, under State Pension age, and the over-pension-age
YAML case is named for the start of the tax year.

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

Copy link
Copy Markdown
Collaborator Author

Merged main at be877c81c (includes #1949 fc1ecc4d3 and #1943) into this branch, now at head 14f584e8a.

Merge (5ac5c73bf). There were three conflicts:

  • The UC docs notebook: main's cell, with this PR's minimum income floor paragraph put back.
  • uc_individual_earned_income.py: this PR's reg 62(2)/(3) formula is kept. Main's Finance Act 2004 s.188(3)(a) age filter on pension contributions moves to uc_individual_earned_income_before_mif, where this PR takes the deductions. That file is a byte-for-byte copy of Use each rule's own Universal Credit earned income in the benefit cap, targeted childcare and local CTR #1999's (blob 73a93702a), so the two PRs merge in either order.
  • test_uc_earnings_deductions_properties.py: main's file, plus this PR's three changes.

After the merge:

  • 311e50261: the floor's notional Class 4 uses ni_class_4_liable, which Use the State Pension Credit qualifying age, and start-of-year status for Class 4 NI #1907 split out of ni_liable (SI 2001/1004 reg 91(a)). Before this, someone reaching State Pension age between 7 April and 6 October had no Class 4 deducted from the threshold, though they pay it on actual profits. In 2026 that is a 66-year-old: a floor £633.73 too high.
  • 2591125d5: YAML expectations recomputed by hand for Stop stacking the trading allowance on expenses already netted from profit #1881, which gives no trading allowance on a profit above £1,000 when receipts are unknown. The "before" figures come from a real run of main. The case "above the net floor, below the gross threshold" now uses gross receipts. The third-claimant case flags claimants by input, because is_uc_claimant now follows is_claimant_or_partner.
  • c711defaa and 14f584e8a (tests only): the property tests draw pension ages from 65. Two explicit examples (a 66-year-old in 2026, under both NI bases) always run; the self-employed one fails on the previous formula.

Review. Independent Opus reviews via Subfleet:

  • 20260930-221418 approved baff2d793.
  • 20261004-103929 asked for changes at 2591125d5: the Class 4 liability fix, and stale PR-body claims.
  • 20261004-121709 approved c711defaa.
  • 20261004-131831 approved 14f584e8a.
  • Every note from those reviews is addressed in the code or in the body.

Tests:

  • Local: UC YAML folder 264/264; income_floor 31/31; uc_earnings_deductions.yaml 14/14; the floor property tests 6/6 at c711defaa; ruff format --check and ruff check clean.
  • CI: all checks green on 14f584e8a.

Impact. Re-run as three real Enhanced FRS runs: base main be877c81c, branch c711defaa, and the branch on the Class 1 basis. 2026 UC rises £0.270bn (Class 1 basis: £0.294bn). The body has the full table and decomposition.

🤖 Generated with Claude Code

@MaxGhenis
MaxGhenis merged commit 88a2450 into main Oct 4, 2026
7 checks passed
@MaxGhenis
MaxGhenis deleted the uc-mif-net-floor branch October 4, 2026 18:14
MaxGhenis added a commit that referenced this pull request Oct 4, 2026
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>
MaxGhenis added a commit that referenced this pull request Oct 5, 2026
…age changes moved

- Three cases with £15,000 of profit (uc_mif_earned_income.yaml, "the
  elder nominated by default"; uc_is_responsible_carer.yaml, "works more
  hours" and "a recorded nomination"): main's #1880 fix gives no trading
  allowance relief on a profit above £1,000 when gross receipts are not
  given, so income tax is (15,000 - 12,570) x 20% = 486, not 286, and
  earnings before the floor are 14,368.20. The floored partner is
  20,386.03 - 14,368.20 = 6,017.83, and 30,960.75 - 14,368.20 = 16,592.55
  where the nominated carer has a 16-hour threshold.
- uc_minimum_income_floor.yaml, main's #1973 case for someone reaching
  State Pension age after 6 April: at 66 they are over State Pension Credit
  qualifying age, so in section 19 (reg. 89(1)(a)) with no threshold. Set
  the group as the age-70 case does, to keep testing the notional Class 4.

Review: vahid-ahmadi on #2081, item 1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit that referenced this pull request Oct 5, 2026
…text

- uc_mif_earned_income.yaml, "Couple from gross incomes": the children
  became 15 and 14 in this PR (to keep 35 expected hours), and the
  universal_credit line was dropped. Both were born before 6 April 2017, so
  the first has the higher child element: uc_maximum_amount is 666.97 x 12 +
  (351.88 + 303.94) x 12 + 12,000 = 27,873.48 and universal_credit is
  27,873.48 - 0.55 x 35,648.06 = 8,267.05.
- universal-credit.ipynb: the nomination default ends with the elder and
  hours_worked defaults to 0; the responsible carer's hours are 30 only from
  February 2025 (16 and 25 from April 2017); the couple threshold includes
  35 hours at the national living wage for a reg. 3(3) partner.

Review: independent review of 5ed0fd4, findings 3 and 4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit that referenced this pull request Oct 6, 2026
…-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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

UC earned income deducts the whole benefit unit's tax, including tax on pensions and other unearned income

1 participant