Skip to content

Count statutory sick, maternity and paternity pay as Universal Credit earned income - #2365

Merged
MaxGhenis merged 3 commits into
mainfrom
uc-statutory-pay-2337
Oct 12, 2026
Merged

MaxGhenis merged 3 commits into
mainfrom
uc-statutory-pay-2337

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 12, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #2337. Also fixes defect 3 of #1997.

What and why

Universal Credit treats statutory sick, maternity and paternity pay as employed earnings: UC Regs 2013 reg. 55(4)(a) to (c). Reg. 55(5) deducts income tax and primary Class 1 NI from "the amount of general earnings or benefits specified in paragraphs (2) to (4)". The regulations leave no second reading.

The model already charged NI on all three payments and income tax on sick and maternity pay, and deducted both from UC earned income. But uc_individual_earned_income_before_mif left the payments out of earned income, so the tax and NI on them came off other earnings. UC rose by 0.55 × (20% + 8%) = 15.4p per pound of sick or maternity pay above the thresholds, and by 4.4p per pound of paternity pay.

Changes:

  • uc_individual_earned_income_before_mif adds statutory_sick_pay, statutory_maternity_pay and statutory_paternity_pay to earnings. Reg. 55(4) also lists adoption, shared parental, parental bereavement and neonatal care pay, but the model has no variables for those.
  • statutory_paternity_pay is now in HOUSEHOLD_BENEFIT_VARIABLES, both HBAI lists and GOV_SPENDING_VARIABLES, next to statutory_maternity_pay. Sick and maternity pay were already in all four lists; paternity pay was in none. Once UC tapers paternity pay, leaving it out would make household net income fall as the pay rose: £400 of pay would cut UC by £220 and never count as income. uk-data does not fill statutory_paternity_pay, so this moves no survey aggregate.

Invariants (Hypothesis properties in tests/test_uc_statutory_pay_properties.py, plus deterministic paths)

  1. Monotonic. Raising a claimant's statutory pay, with everything else fixed, never raises UC before the benefit cap. The final award rises only where the family becomes exempt from the cap. Three exceptions are lawful, each tested and labelled:
    • Childcare work condition. Reg. 32(2)(b) treats a person on statutory pay as in paid work, so the first pound can open the childcare element. The award rises by no more than the element.
    • Marriage Allowance cliff. ITA 2007 s. 55B(2)(b) withdraws Marriage Allowance in one step. The test shows the cliff happens and is identical for wages. Families claiming Marriage Allowance are left out of the monotonic property.
    • Benefit cap earnings exception. Under reg. 82(1)(a), a pound of pay can lift the cap. This can't arise in the model yet, because is_benefit_cap_exempt_earnings ignores statutory pay. Use each rule's own Universal Credit earned income in the benefit cap, targeted childcare and local CTR #1999 changes that by reading uc_individual_earned_income_before_mif.
  2. Same as wages. Sick or maternity pay of s on top of wages of e gives the same income tax, NI, earned income and pre-cap award as wages of e + s. Paternity pay is left out until the model taxes it (Charge income tax on statutory paternity pay #2368). So are recipients whose pension relief is capped by earnings, because the model's relief excludes statutory pay.
  3. Accounting. Earned income before the minimum income floor = wages + statutory pay + trading profit (a loss counts as nil) − relievable pension contributions − tax on earnings − NI on earnings, floored at nil.
  4. Bounds. A pound more of pay adds between nothing and a pound to the recipient's earned income.
  5. Claimants only. A dependant's statutory pay changes neither the claimants' earned income nor the award (reg. 22(1)(b)).
  6. Counted once. Each payment counts once in household_benefits: Δhousehold_benefits − Δ(other listed benefits) = Δpay. Each payment appears exactly once in all four lists.

Power: on unfixed main, 6 of the 7 original YAML cases and 4 of the 6 original properties fail. The other 2 are controls: the dependant property and the childcare exception. With paternity pay removed from household_benefits, invariant 6 and the list check fail.

Impact

Measured at the pre-merge head 0dce50c against its base, main 3f174d0. Since then the only change is a merge of main (0654c4c), which brought in main's own changes, including #2327's switch to taxable_miscellaneous_income in the same list. Real run, 2026, one Microsimulation each. Both runs use the certified enhanced FRS: uk-data 1.58.0, enhanced_frs_2024_25.h5, HF revision 47bbb58d, sha256 5ba399ea…d960b6, verified at load. Main is 3f174d0; this branch is 0dce50c, a clean tree. The runs went through the heavy lock, one at a time. Script and outputs: ~/reviews/uk-statutory-pay-gov-spending-2026-10-12/ (impact.py, compare.py, runs/).

2026, £bn Main This branch Change
universal_credit 83.589 83.365 −0.225
household_benefits 552.579 552.354 −0.224
household_net_income 1,710.908 1,710.684 −0.224
gov_spending 552.208 551.984 −0.224
gov_balance 469.236 469.460 +0.224
benefit_cap_reduction 1.171 1.155 −0.016
gov_tax 1,021.444 1,021.444 0
  • Who loses UC. 73 sample households (67k weighted) lose UC: 40 receive SSP and 33 SMP. No household gains. Among them, UC falls by £0.39 per £1 of statutory pay; the median pay is £6,444 a year and the largest fall is £10,235 a year. Main's error was +£0.154 per £1 for pay above the thresholds, so the move is the taper less that error, smaller where pay is under the work allowance or the minimum income floor.
  • Benefit cap. Capped families' pre-cap UC falls, so the cap takes £0.016bn less.
  • Tax-Free Childcare. In 2 sample households (672 weighted), UC falls to nil and household benefits fall £619.74 less than UC. That fits Tax-Free Childcare becoming payable: the model withholds it while the benefit unit has any pre-cap UC (disqualifying_benefits.yaml, Childcare Payments Act 2014 s. 11). These runs did not record that variable.
  • No paternity-pay effect. uk-data does not fill statutory_paternity_pay, so adding SPP to the household lists moves nothing here.
  • Data caveat. uk-data sets SSP and SMP from the FRS weekly amounts × 52 (policyengine_uk_data/datasets/frs.py), so a payment current at the interview counts for the whole year. That is a data-side convention this PR does not change.

Tests run locally

At the merged head 0654c4c: test_uc_statutory_pay_properties.py and test_aggregation_lists.py, 15 passed. Sol's round-3 review also ran uc_statutory_pay.yaml there: 9 passed. The rest below ran at 0dce50c.

  • uc_statutory_pay.yaml: 9 passed. Expected values are hand-computed from the 2026-27 rates in the file header, and every one was re-derived by the reviewer.
  • test_uc_statutory_pay_properties.py: 7 passed in 38 s. A randomized stress run also passed at the original head 70851ab: 200 random populations for the monotonic property and 150 for wages and accounting. It wasn't repeated at 0dce50c.
  • YAML folders: universal_credit 423, household 135, benefit_cap 8, council_tax_reduction 173, dfe 218, plus 140 cases in 11 other YAML files that read statutory pay or the lists. All passed.
  • test_aggregation_lists.py, test_household_benefits_properties.py, test_uc_childcare_work_condition_properties.py, test_council_tax_reduction_pension_credit_properties.py: 27 passed.
  • ruff format --check and ruff check pass on every changed Python file.

Review

GPT-6.1 Sol (subfleet run --task review --tier hard):

  • Round 1 at 70851ab requested changes, with two blocking findings: paternity pay was missing from household income, and the final-UC monotonic property was false under reg. 82. Both are fixed in 0dce50c.
  • Round 2 approved head 0dce50c.
  • Round 3 reviewed the merge of main, whose one conflict was Relieve a miscellaneous loss only against miscellaneous income #2327's taxable_miscellaneous_income in the same list. It approved head 0654c4c: both changes are kept, and nothing main brought in changes an expected value or property.

Reviews are in ~/reviews/uk-statutory-pay-gov-spending-2026-10-12/review/ (out_2365.md, out_2365_r2.md, out_2365_r3.md). Its non-blocking suggestions:

Interactions

Ownership: no W1 file (simulation.py, tax_benefit_system.py, utils/scenario.py, utils/parameters.py) and no W3 file (tests/conftest.py, aggregate-impact.yaml, reforms_config.yaml) is touched.

axiom: TheAxiomFoundation/rulespec-uk#387 queued. Reg. 55 is not in the pinned corpus release, so the signed encoder can't cite it yet. The statutory-pay leaves and companion cases are added there.

🤖 Generated with Claude Code

Reproducer: policyengine_uk/tests/policy/baseline/finance/benefit/family/universal_credit/income/uc_statutory_pay.yaml, policyengine_uk/tests/test_uc_statutory_pay_properties.py::test_award_never_rises_with_a_claimants_statutory_pay, policyengine_uk/tests/test_uc_statutory_pay_properties.py::test_each_payment_is_household_income_and_government_spending, policyengine_uk/tests/test_uc_statutory_pay_properties.py::test_statutory_pay_counts_as_wages_and_earned_income_adds_up, policyengine_uk/tests/test_uc_statutory_pay_properties.py::test_a_dependants_statutory_pay_is_not_the_claimants_earned_income, policyengine_uk/tests/test_uc_statutory_pay_properties.py::test_award_falls_along_a_path_of_rising_statutory_pay

UC Regs 2013 reg. 55(4) treats statutory sick, maternity and paternity pay
(and adoption, shared parental, parental bereavement and neonatal care pay,
which the model has no variables for) as employed earnings, and reg. 55(5)
deducts tax and primary Class 1 NI from "the amount of general earnings or
benefits specified in paragraphs (2) to (4)". The model deducted the tax
and NI on these payments from earned income but left the payments out, so
Universal Credit rose by 15.4p per pound of sick or maternity pay above
the thresholds.

Adds YAML cases and Hypothesis properties: the award never rises with a
claimant's statutory pay (two intended exceptions executed and labelled:
reg. 32(2)(b) childcare work condition, ITA 2007 s. 55B(2)(b) Marriage
Allowance cliff), sick and maternity pay count exactly as wages, earned
income adds up, and a dependant's pay is not the claimants'.

Fixes #2337

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of 70851ab (GPT-6.1 Sol) found two blocking problems:

- Statutory paternity pay was in no household income list, while statutory
  sick and maternity pay were. Once Universal Credit tapers it, household
  net income fell as paternity pay rose (UC -220 on 400 of pay, with the
  pay never counted). Add it next to maternity pay in household_benefits,
  both HBAI lists and gov_spending, and add a net income regression.
- The monotonic property checked the award after the benefit cap. Reg.
  82(1)(a) lifts the cap once earned income reaches the threshold, and
  statutory pay is earned income, so a correct cap would fail it. Check the
  award before the cap, and let the final award rise only where the family
  becomes exempt.

Also: prove the Marriage Allowance cliff directly, qualify it for Scottish
taxpayers, add a property that each payment counts once in
household_benefits, add a YAML case where NI on paternity pay is deducted,
and correct the comment and changelog: income tax falls on sick and
maternity pay only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflict in uc_individual_earned_income_before_mif: main (#2327,
7145d5b) counts taxable_miscellaneous_income instead of
miscellaneous_income; this branch adds statutory sick, maternity and
paternity pay. Both are kept.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis
MaxGhenis marked this pull request as ready for review October 12, 2026 09:12
@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Hand-off to the UK hub from session local_615fdd79-8fa2-4544-b8ce-67188d179ad6 (started by the UK hub).

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

UK hub (2026-10-12): this PR's head 0654c4c9b is merged unchanged into rollup B, #2380, with #2365, #2366 and #2375. Its one CI run tests all three together on current main. Merging #2380 with a merge commit marks this PR merged. The hub cancelled this PR's own queued runs, which the rollup replaces, to free slots in the starved Actions queue. Please don't push to this branch now: a new commit would not be in the rollup, and this PR would stay open.

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.

Universal Credit rises with SSP and SMP: tax on them is deducted but they aren't counted as earnings

1 participant