Stop stacking the trading allowance on expenses already netted from profit - #1881
Conversation
…rofit self_employment_income is profit after expenses (FRS SEINCAM2; SPI PROFITS "gross profits assessable"), but trading_allowance_deduction subtracted min(1000, profit) from it. Under ITTOIA 2005 Part 6A the allowance is measured against gross receipts (s. 783AC) and replaces actual expenses and capital allowances (ss. 783AE-783AF full relief, s. 783AI partial relief; HMRC BIM86050), so the old formula gave up to 1,000 of double relief to every self-employed person with profits above the allowance. The deduction is now the allowance's excess over actual expenses and capital allowances, capped at profit, when the new optional self_employment_gross_receipts input is supplied. Without receipts, a profit within the allowance gets full relief and a larger profit gets none. The allowance parameter now starts in 2017-18 (F(No.2)A 2017 Sch 3 para 13). Fixes #1880 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Treat gross receipts below profit as unknown rather than as zero expenses. - Document the discontinuity at the allowance when receipts are unknown. - Property tests now draw losses, loss relief and receipts below profit, and fix the Part 6A reference in the docstring. - Refresh the saved docs notebook output for the trading allowance row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Axiom status for this fix. Axiom does not yet encode the trading allowance, so this PR has no Axiom differential check yet. Tracking is in TheAxiomFoundation/rulespec-uk#348. The statutory reading was checked independently against legislation.gov.uk ITTOIA 2005 Part 6A Chapter 1, and it agrees with this PR:
So The Axiom encoding needs the Chapter ingested into the Axiom corpus first. Only s.783A is there today, and outside the pinned UK release. Once encoded, Axiom will compare it against the fixed release on a receipts/expenses grid. |
…-double-relief # Conflicts: # uv.lock
|
Impact re-measured on current main for the merge train (corrected 2 October, 21:15Z). These are real Microsimulation runs on the published Enhanced FRS 2024-25 (1.57.4, sha256
The change passes £1bn a year in 2031-32. An earlier version of this comment said that put the merge with Max. He has since removed the size line from the merge-on-gates rule (decision d849 is closed as "merge on gates"), so this PR lands on its gates. |
|
Merged at
#1919 (Class 4 NICs on Chapter 2 profits) is stacked on this. |
- #1950: rent and dividends are not UC unearned income (reg. 66(1) is a closed list), so the single parent's unearned income is nil (UC 11,308.50) and the self-employed claimant's is the pension alone (UC 3,975.29). - #1881: without gross receipts, a trade profit above the trading allowance gets no allowance (ITTOIA 2005 s. 783AI), so the tax on the trade is (18,000 - 12,570) x 20% = 1,086. The tax and NI this PR deducts are unchanged in method; the cases' gaps against the pre-fix formula are still 0.55 x the tax on other income. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fixes #1880
What was wrong
trading_allowance_deductionsubtractedmin(£1,000, self_employment_income)fromself_employment_income. That input is profit after expenses, so the allowance was stacked on expenses already deducted. The trading allowance is in ITTOIA 2005 Part 6A Chapter 1, ss. 783A–783AR;/part/7Adoes not exist on legislation.gov.uk. It is measured against gross receipts ("relevant income", s. 783AC). It replaces actual expenses and capital allowances rather than adding to them:Example, 2027: a £25,000 profit gave
income_tax£2,286 onadjusted_net_income£24,000. The correct figure is £2,486 on £25,000.What the data represent
Neither source contains gross receipts. Every self-employment value in the enhanced FRS is a profit net of expenses:
self_employment_income = max(0, SEINCAM2) × 365.25/7(policyengine-uk-datadatasets/frs.py). DWP defines FRS self-employment earnings as "gross of tax and national insurance payments, based on profits ... or on estimated drawings otherwise" (Stat-Xplore FRS metadata).PROFITS. The SPI Public Use Tape documentation (UKDS SN 9422, 2022-23) defines it as "Gross profits assessable for all sources of self-employment income". Self-employed income there ismax(0, PROFITS – CAPALL – LOSSBF).In the published enhanced FRS 2024-25 (1.56.16),
capital_allowancesandloss_relieftotal £0.The fix
A new optional input,
self_employment_gross_receipts, lets callers who know turnover get the exact statutory result. With profit P, receipts R, expenses E = R − P and capital allowances CA:trading_allowance_deductionmax(0, min(P, 1000 − E) − CA)R − max(E + CA, £1,000). This is exactly the better of the profit method and the allowance.P − CAif P ≤ £1,000, otherwise 0Why keep full relief for small profits when receipts are unknown? In the published dataset, 0.198m people (2026) have profits of £1,000 or less. About 0.16m of them are employees, retired or disabled people with side income, and 0.04m are mainly self-employed. Keeping full relief also leaves the familiar "£1,000 of side income is tax-free" case unchanged. The cost is a known discontinuity at £1,000 when receipts are unknown: tax stays non-decreasing but jumps there. Supplying receipts removes it. The variable documentation states this.
Also in this PR:
Invariants (stated and property-tested)
policyengine_uk/tests/test_trading_allowance_properties.pyuses Hypothesis, 40 examples per property with 24 cases each. The draws are weighted towards the £1,000 boundary and the tax thresholds.0 if R ≤ 1000 else max(0, R − max(E + CA, 1000) − loss relief). With unknown or inconsistent receipts, taxable profit =0 if P ≤ 1000 else max(0, P − CA − loss relief).income_taxis non-decreasing in profit at fixed expenses and capital allowances, across employment incomes from £0 to £200k.Cases include losses (profit down to −£5,000), loss relief, and receipts drawn below profit.
Mutation checks:
main's formula restored, properties 1–3 fail. It returns negative relief on losses and stacks on expenses.Revenue effect (microsimulation, before vs after)
Real Microsimulation runs on 2 October 2026:
main3c48247eagainstmainmerged with this head (0cbcc78c), on the published Enhanced FRS 2024-25 (1.57.4, sha25603fe15e4…). One run per version and year.About 3.5m households pay more income tax. Class 4 NICs are unchanged, since they already use unreduced profit. This moves baseline income tax by about £0.9–1.0bn a year.
Earlier runs (30 September
main, dataset 1.56.16) gave the same picture: the deduction fell from £4.36bn to £0.12bn in 2026, and income tax rose £0.89bn (2026) to £0.98bn (2030).Known limits (not changed here)
self_employment_income. They ignore capital allowances and loss relief, and the allowance when receipts are supplied. The statute taxes the same Chapter 2 profit (SSCBA s. 15(1)(b); BIM86052). Follow-up.property_allowance_deductionhas the same stacking bug:INCPROPis "Net income from UK and overseas property (income - expenses)". It also cites a trading section and starts in 2005. Follow-up.loss_reliefis still built fromtrading_lossand is not limited by the allowance. Taxable profit is floored at zero, so tax is unaffected unless losses carry forward. This was already the case.Tests run
policyengine-core test policyengine_uk/tests/policy/baseline/gov/hmrc: 443 passed. This folder held all 12 full-suite failures on the first run (1242 passed).pension_contributions_relief.yaml(£30k profit now £3,486 = (30,000 − 12,570) × 20%),child_benefit_hitc.yamlandtaxable_self_employment_income.yaml.pytest policyengine_uk/tests/test_trading_allowance_properties.py: 4 passed, 40 examples each.ruff format --check .andruff check .: clean.hypothesisis already a dev dependency onmain, so this PR no longer touchespyproject.tomloruv.lock.main(0cbcc78), the fullpolicyengine-core test policyengine_uk/tests/policyrun passes (1,277 tests), as do the property tests and ruff.income-tax.ipynbnow shows the current value (£1,000 from 2017-04-06). Other rows in that cell still show each parameter's earliest value, which was already the case.Independent review
An Opus 5.5 reviewer ran on a Subfleet
review/standardlane with a read-only sandbox, and returned APPROVE. It hand-checked the statute and every updated expectation. It could not execute code, so the test runs, mutation checks and revenue figures above are this session's own. A delta re-review of 113c6f7 also returned APPROVE; its one actionable minor finding, a YAML case for receipts below profit, is added. The first review's minor findings are all addressed in 113c6f7: inconsistent receipts, the discontinuity doc, wider property tests, the s. 783AK(4) wording, the docstring and the notebook output.axiom: TheAxiomFoundation/rulespec-uk#348 queued
🤖 Generated with Claude Code