Repository navigation
Count statutory sick, maternity and paternity pay as Universal Credit earned income - #2365
Merged
Merged
Conversation
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>
This was referenced Oct 12, 2026
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>
This was referenced Oct 12, 2026
MaxGhenis
marked this pull request as ready for review
October 12, 2026 09:12
Collaborator
Author
|
Hand-off to the UK hub from session local_615fdd79-8fa2-4544-b8ce-67188d179ad6 (started by the UK hub).
|
Collaborator
Author
|
UK hub (2026-10-12): this PR's head |
This was referenced Oct 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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_mifleft 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_mifaddsstatutory_sick_pay,statutory_maternity_payandstatutory_paternity_payto 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_payis now inHOUSEHOLD_BENEFIT_VARIABLES, both HBAI lists andGOV_SPENDING_VARIABLES, next tostatutory_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 fillstatutory_paternity_pay, so this moves no survey aggregate.Invariants (Hypothesis properties in
tests/test_uc_statutory_pay_properties.py, plus deterministic paths)is_benefit_cap_exempt_earningsignores statutory pay. Use each rule's own Universal Credit earned income in the benefit cap, targeted childcare and local CTR #1999 changes that by readinguc_individual_earned_income_before_mif.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_incomein 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, sha2565ba399ea…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/).universal_credithousehold_benefitshousehold_net_incomegov_spendinggov_balancebenefit_cap_reductiongov_taxdisqualifying_benefits.yaml, Childcare Payments Act 2014 s. 11). These runs did not record that variable.statutory_paternity_pay, so adding SPP to the household lists moves nothing here.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.pyandtest_aggregation_lists.py, 15 passed. Sol's round-3 review also ranuc_statutory_pay.yamlthere: 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.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 --checkandruff checkpass on every changed Python file.Review
GPT-6.1 Sol (
subfleet run --task review --tier hard):taxable_miscellaneous_incomein 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
TAXED_AS_WAGESin this PR's property test. No file overlap.uc_individual_earned_income_before_miffor the benefit cap earnings exception, so the cap counts statutory pay once both land. Exception (c) above is written for that. Whichever lands second should rerun its tests.gov_spending.py, in a different hunk. Its code-health test (household benefits ⊆ government spending) passes with this PR, because SPP goes into both lists.statutory_paternity_payspending head; see the comment on #2335.pawhp) edits other lines of the same lists. No conflict.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