Repository navigation
Disregard allowable employment expenses in Universal Credit earnings - #2494
Open
juaristi22 wants to merge 1 commit into
Open
juaristi22 wants to merge 1 commit into
juaristi22 wants to merge 1 commit into
Conversation
vahid-ahmadi
left a comment
Collaborator
There was a problem hiding this comment.
Fine once expenses can no longer push employed earnings below nil.
@juaristi22, the change follows UC Regs 2013 reg 55(3)(a), which disregards expenses allowed under ITEPA Part 5 Chapter 2. I hand-checked the main case. The 2024 single standard allowance is £4,721.40. Then 4,721.40 − 0.55 × 5,400 = £1,751.40, and the gain against the case with no expenses is 0.55 × 600 = £330.
- should:
uc_individual_earned_income_before_mif.py:106-121.employedis not floored before it is added toself_employed, so expenses above employment income now reduce self-employed earnings. With 2025 inputs of £1,000 employment income, £3,000employment_expensesand £10,000 self-employment income,taxable_employment_incomeis £0, but UC earned income is £8,000 instead of £10,000. ITEPA s.329(1) says a Part 5 deduction "may not exceed the earnings from which it is deductible", andtaxable_employment_incomealready floors at nil. Cap the expenses at the employment earnings, or flooremployedat nil before adding the trade figure. - should:
employment_expensesis not only a household-calculator input. policyengine-uk-data imputes it onto the FRS from the SPI (datasets/imputations/income.py:38,employment_expenses="EPB"). So this changes population UC results, not only the household cases in the tests. The PR body says population impacts were not tested. A one-line estimate in the PR, or a note in the changelog that microsimulation results move, would help whoever reviews the data release. Point 1 matters more here, because imputed values are not bound by s.329. - nit: the UC reg 55(3)(a) reference reuses the same URL as the existing reg 55(4)/(5) entry. One entry titled "reg. 55(3)(a), (4) and (5)" would do.
What I checked
- Read the full diff and issue #1997. Read reg 55 on legislation.gov.uk and ITEPA s.329.
policyengine-core test uc_employment_expenses.yaml: 2 passed.pytest test_uc_employment_expenses.py: 16 passed. All oftests/policy/baseline/finance/benefit/family/universal_credit: 484 passed.- Reverted the UC formula. The new YAML then fails 1 of 2, and the new pytest file fails 12 of 16.
- Ran the over-deduction household above, on this head.
ruff checkandruff format --checkon the changed Python files: clean.- Hosted CI on this head: all green.
- Not checked: the notebook render, private-data impacts, and the NI regulations beyond the link.
🤖 Generated with Claude Code
This branch has not been deployed
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.
Refs #1997. This implements the employment-expenses part; payroll giving and any remaining work stay open.
UC employed earnings currently omit the existing
employment_expensesinput even though it reduces taxable employment income. Deduct that specific input before adding separately calculated trading earnings. In the natural 2024 single-claimant test, £6,000 earnings and £600 allowable expenses now produce £5,400 UC earnings and £330 more annual UC. Existing tax/NI and pension deductions, trade floors, statutory pay, MIF, claimant aggregation and supplied-output overrides are preserved.The input represents expenses already allowed under ITEPA Part 5 Chapter 2, after the relevant-employment and combined-deduction restrictions in Chapter 1. Reimbursements qualify only to the extent included in employment earnings; callers must avoid duplicate costs. The input metadata and UC documentation explain this contract. No raw-cost admissibility engine or general salary cap is added. The disregard follows GB regulation 55(3)(a) and its NI counterpart; this validation does not certify every historical commencement or payment-timing case.
Reproducer: policyengine_uk/tests/test_uc_employment_expenses.py::test_allowable_expenses_increase_natural_final_uc_cash
Validation: 151 distinct relevant tests passed across implementation and targeted runs, with unchanged cases carried forward after a fixture correction. Independent captured-head CODE/POLICY review is complete with no findings or material gaps; its 74 fresh tests overlap the implementation results. Formatting, lint, structure/protected-payload checks, the trusted base fix-evidence checker and a notebook HTML build without execution passed. All 807 existing parameter YAML files remain unchanged. Local Python 3.13/Core 3.32.27/microdf 1.2.1 differs from the lock; the full suite, private data, population impacts and encoded parity were not tested. Hosted CI remains to be checked.
The notebook is also touched by #1837 and #1999 in different sections. Preserve those edits when coordinating landing; #1999's downstream earnings-measure work remains separate.
Axiom: needed. The statutory UC expense disregard needs a supported encoding/parity follow-up; no encoding result is claimed.