Skip to content

Relieve trading losses against general income by each programme's rule - #2085

Draft
MaxGhenis wants to merge 5 commits into
mainfrom
self-employment-loss
Draft

MaxGhenis wants to merge 5 commits into
mainfrom
self-employment-loss

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 2, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

A self-employment loss now reaches each programme by that programme's own rule. The loss is entered as trading_loss, a positive amount kept apart from the profit in self_employment_income. That variable already existed but only reduced self-employment income. With this PR:

Programme Rule Model
Income Tax Trade loss relief against general income: the loss is deducted in calculating net income for the loss-making year (ITA 2007 s.64), "limited in accordance with sections 24A and 25(4) and (5)" (s.65(1)), with no partial claim to protect the Personal Allowance trade_loss_relief_against_general_income = min(loss, cap, net_income_before_trade_loss_relief). It reduces adjusted_net_income, so the PA taper, HICBC, tapered annual allowance, Tax-Free Childcare and 30-hours tests, CGT bands and self-assessment student loan repayments (SI 2009/470 reg 29(4)(h)) all see it
s.24A cap "£50,000, or ... if more, 25% of the taxpayer's adjusted total income" (s.24A(5)), from 2013-14. Adjusted total income (s.24A(8)): total income, plus payroll giving, less pension contributions given relief income_tax_relief_cap; adjusted_total_income = taxable income components (losses brought forward added back, being a Step 2 relief) less the person's own contributions up to the greater of £3,600 and relevant UK earnings (taxable pay, benefits and statutory pay, plus chargeable trading profits; s.189(2)), none from age 75 (FA 2004 ss.188(3)(a), 190)
Order of deduction s.25(2): "in the way which will result in the greatest reduction"; from 2027-28 s.25(3A) (FA 2026 s.6): income other than property, savings and dividends first Non-savings income first (property last), then savings, then dividends: the order the model already uses for the Personal Allowance. The part beyond non-savings income is trade_loss_relief_against_savings_and_dividends. That fixed order can overcharge where savings are taxed at 0%, for the Personal Allowance as much as for this relief: #2106
Class 4 and Class 2 NICs Losses reduce Class 4 profits only; a deduction against general income "shall ... be treated ... as reducing the person's profits for that year of any relevant trade", and any excess is carried forward for Class 4 (SSCBA 1992 Sch 2 para 3(4)); Class 2 "relevant profits" are the Class 4 profits (s.11(3)) ni_class_4_profits = max(0, profits − losses brought forward − the year's relief − ni_class_4_losses_brought_forward), read by ni_class_4, ni_class_4_main, ni_class_4_maximum, ni_class_2. The new input holds para 3(4)(b) losses that Income Tax set against other income
Tax credits "If there has been a trading loss in the year, subtract the amount of that loss from the result of Step Three" (SI 2002/2006 reg 3(1) Step Four); a joint claim aggregates both claimants' incomes tax_credits_applicable_income less the claimants' losses (not a child's), never below zero
UC Reg 57(2) Steps 1-2 add the profit or loss of each trade; Step 3: "If the amount resulting from steps 1 to 3 is nil or a negative amount, the amount of the person's self-employed earnings in respect of the assessment period is nil" uc_trading_losses_set_against_profits = min(loss, profits): deducted in uc_mif_capped_earned_income before the minimum income floor and in the reg 82 benefit cap earnings tests; never against employed earnings
HB, CTR, Pension Credit, IS, JSA, ESA "any loss incurred in any one of his employments shall not be offset against his earnings in any other of his employments" (HB reg 38(10); IS reg 38(11); JSA reg 101(12); ESA reg 98(11); Pension Credit through SPC reg 17B(5)(b) and SI 1996/2745 reg 13(12); HB(SPC) reg 39(9); CTR SI 2012/2885 Sch 1 para 29(9), SI 2012/2886 para 61(10)) None of them reads trading_loss; self_employment_income stays non-negative
HBAI "profit or loss from self-employment (losses are treated as a negative income)" (HBAI methodology FYE 2025) hbai_household_net_income, household_market_income and market_income subtract it

loss_relief now holds only losses brought forward (s.83: "a deduction for that purpose is to be made only from profits of the trade"), which is how policyengine-uk-data's SPI build already fills it (LOSSBF). It no longer adds the previous year's trading_loss automatically, because the new relief may already have used that loss against general income. trading_loss is uprated like self-employment income (variable uprating and uprating_indices.yaml), and it moves from bases/ to input/.

Fixes the loss part of #1916 (capital allowances and the trading allowance stay open there). Companion data: PolicyEngine/policyengine-uk-data#528 fills trading_loss from FRS SEINCAM2 < 0.

Choices and limits

  • The claim. The model assumes the trade is commercial (s.66), that the person claims, and that the claim is for the loss-making year (not carried back, s.64(2)(b)). The s.74A £25,000 cap for non-active traders is not modelled.
  • Carry-forward. The unrelieved part of a loss is carried forward only by entering it in loss_relief (both taxes) or ni_class_4_losses_brought_forward (Class 4 only) in later years. Computing it automatically would need each earlier year's whole Income Tax calculation.
  • Adjusted total income leaves out payroll giving, which the model does not have. It applies the s.190 relief limit directly rather than reading pension_contributions_relief, which depends on adjusted net income through the tapered annual allowance (a cycle) and also caps relief at the annual allowance, which in law charges excess saving rather than limiting relief.
  • UC trades are netted over the year, as if the profits and the loss accrue evenly; reg 57 works per assessment period and carries unused losses forward (reg 57A).
  • Means tests and the tax they deduct. The law deducts tax actually deducted or paid in the period: "any amount deducted from those earnings by way of ... income tax" (HB and IS reg 36(3)(a)); "any amounts paid by the person in that period ... by way of income tax" (UC reg 55(5)(b)). A refund is capital (IS reg 48(2), HB reg 46(2)). The model's means tests deduct the year's Income Tax liability, so the relief lowers the tax they deduct, as Gift Aid and other self-assessment reliefs already do. That gap is model-wide: Means tests deduct the year's Income Tax liability, not the tax deducted from earnings (HB/IS reg 36(3), UC reg 55(5)) #2108. Its size for this change is in the impact section. The property tests pin the boundary: with Income Tax and NI held, the means tests are what they are without the loss, apart from UC's netting of trades.
  • HBAI resets a negative household BHC income to zero; the model never has. Losses make negative incomes slightly more common (impact below); a follow-up task covers the reset.

Invariants (property-tested with Hypothesis, test_trading_loss_properties.py)

  1. Relief definition: relief = min(loss, max(£50,000, 25% × adjusted total income), net income). Net income comes from a separate simulation without the loss; adjusted total income is that less the relieved pension contributions computed outside the model. Adjusted net income falls by exactly the relief.
  2. Differential: a person's Income Tax with a loss equals the Income Tax of the same person with no loss and their pay, pension, savings and dividends cut by the relief in the model's order (an outside-the-model reference; Allowances and reliefs are set against savings before dividends, not in the order giving the greatest reduction (ITA 2007 s.25(2)) #2106 for the order itself).
  3. Monotone and bounded: Income Tax never rises with the loss; it falls by at most the relief, for people without savings income (the personal savings allowance rises £500 when someone stops being a higher-rate taxpayer, so with savings income a small relief can save more than itself).
  4. Means tests: with Income Tax, NI and UC held at the values the loss gives, HB, CTR, Pension Credit, IS, income-based JSA, income-related ESA and their income tests are exactly what they are without the loss. UC equals the same family with no loss and each person's profits cut by min(loss, profits).
  5. Tax credits: applicable income falls by the claimants' losses (children have losses too in the generator), never below zero; the award never falls.
  6. Household income: market income falls by exactly the household's losses; HBAI net income moves only through the loss, taxes and means-tested or passported benefits (every other HBAI component unchanged).
  7. Class 4: profits = max(0, profits − losses brought forward − relief); Class 4 never rises with the loss and is nil with no profits.
  8. The cap starts in 2013-14.

Mutation check (one planted bug at a time in a scratch worktree, each run against the test that should catch it): 19 of 19 caught on f658a97, including the round-1 and round-2 fixes (UC netting and the benefit cap earnings test, children's losses in tax credits, relevant UK earnings, the age-75 rule, the s.190 limit, taxable basic income, the Class 4-only carry-forward). Each property runs 3 generated examples plus pinned cases (relief limited by net income, both caps, a loss beside pay or profits, income spilling into savings and dividends, the benefit-cap household, a child's loss), which keeps it to about 2-6 minutes.

Tests

  • YAML: reliefs/trade_loss_relief_against_general_income.yaml (cap at 25% and at £50,000; pension contributions, employment expenses and losses brought forward in adjusted total income; no relief on contributions from 75; Personal Allowance restored; PA wasted; overflow to savings then dividends; taxable basic income), reliefs/loss_relief.yaml (rewritten for s.83), national_insurance/class_4/ni_class_4_trading_loss.yaml (incl. the Class 4-only carry-forward), universal_credit/uc_trading_loss.yaml, tax_credits/tax_credits_applicable_income_trading_loss.yaml (incl. a child's loss), household/income/trading_loss_household_income.yaml.
  • Full YAML suite: 1,676 passed locally on 65735bb; the property file passes on f658a97 (8 tests).

Impact

Real enhanced FRS runs, 2025-26 to 2030-31, of this branch at 65735bb (the figures are identical at 905b41a) on one seeded build of the companion PolicyEngine/policyengine-uk-data#528 (94bd3d7). Each comparison uses the same build, so the weights are identical. Aggregates only; any cell resting on fewer than 10 FRS households is suppressed.

  1. No losses, so no change. On the build with trading_loss zeroed, this branch and main (84f5ad4) give identical results: 38 arrays of taxes, NICs, benefits, household incomes and poverty flags, in every year.
  2. The data's losses under main change nothing but the input itself. Main reads trading_loss only as a deduction from self-employment income, and every loss-maker has none.
  3. This branch with the losses, against the same build with losses zeroed:
2025-26 2026-27 2030-31
Trading losses in the data £319m £330m £387m
Trade loss relief against general income £77m £80m £102m
of which set against savings and dividends £5.4m £5.6m £6.7m
Income Tax −£13.1m −£14.0m −£18.4m
NICs (incl. Class 2 and 4), student loan repayments £0 £0 £0
UC, HB, CTR, Pension Credit, IS, JSA, ESA, tax credits, benefit cap £0 £0 £0
HBAI household net income −£306m −£316m −£368m
Household market income −£319m −£330m −£387m

In 2026-27, 27,000 people (61 FRS households) have a loss; 23,500 (50 households) get relief; for 6,700 (13 households) income or the cap limits the relief below the loss; 9,100 (35 households) pay less Income Tax. No means-tested benefit changes, so the tax-deduction gap in #2108 is £0 on this data. Fewer than 10 FRS households cross a poverty line, so those counts are not published.

The enhanced FRS carries less loss than the raw FRS (£314m on 27,000 people in 2024, against £1.28bn on 74,000), because calibration gives FRS loss-makers about a third of their survey weight; #528 explains.

Review

axiom: TheAxiomFoundation/rulespec-uk#429 queued

🤖 Generated with Claude Code

trading_loss (a loss as a positive amount, separate from the profit in
self_employment_income) now reaches each programme by its own rule:

- Income Tax: trade loss relief against general income (ITA 2007 s.64)
  reduces net income, and so adjusted net income, for the loss-making year.
  It is limited to net income (s.25(4)) and to the s.24A cap, the greater
  of £50,000 and 25% of adjusted total income (s.24A(5), (8)). It comes off
  non-savings income first, then savings, then dividends.
- Class 4 and Class 2 NICs: the relief reduces trading profits only
  (SSCBA 1992 Sch 2 para 3(4); s.11(3) relevant profits), with losses
  brought forward (loss_relief, s.83).
- Tax credits: the claimants' losses come off their income
  (SI 2002/2006 reg 3(1) Step 4).
- Market income and HBAI household income count the loss as negative
  income.
- Means tests read neither the loss nor anything net of it, so it never
  offsets other earnings (UC reg 57, HB reg 38(10), IS reg 38(11) etc.).

loss_relief now holds only losses brought forward (s.83). It no longer
adds the previous year's trading_loss, which relief against general income
may already have used. trading_loss is uprated like self-employment income.

Tests: YAML cases for the relief, cap, ordering, Class 4, tax credits and
household income; Hypothesis properties for the relief definition, a
differential against income cut in s.25 order, monotonicity and bounds,
means tests seeing the loss only through tax, tax credit income, and the
channels HBAI income can move through.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 3 commits October 2, 2026 23:14
…it loss

- adjusted_total_income follows s.24A(8): Step 1 total income (taxable
  components, losses brought forward added back) less own pension
  contributions given relief, up to the greater of £3,600 and relevant UK
  earnings (FA 2004 s.190) and none from age 75 (s.188(3)(a)).
- net_income_before_trade_loss_relief is the one base for adjusted net
  income, the relief limit and the savings/dividends part; it counts basic
  income where a reform makes it taxable.
- UC sets a trading loss against the person's other trades' profits before
  the minimum income floor, never against employed earnings (UC Regs 2013
  reg 57(2) Steps 1-3).
- Tax credits subtract only the claimants' losses, not a child's.
- New input ni_class_4_losses_brought_forward for losses carried forward
  for Class 4 only (SSCBA 1992 Sch 2 para 3(4)(b)).
- The savings-then-dividends order is the model's allowance order, which
  s.25(2) can beat for the Personal Allowance too: documented, #2106.
- YAML cases for each finding; property tests cover UC netting and
  children's losses, with fewer examples for CI time.

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

- uc_trading_losses_set_against_profits (UC Regs 2013 reg 57(2)) is the one
  netting UC earnings and the reg 82 earnings tests in
  is_benefit_cap_exempt_earnings and is_benefit_cap_exempt_health_disability
  deduct, so a loss-maker's cap matches the same household with netted
  profits.
- adjusted_total_income takes relevant UK earnings (FA 2004 s.189(2)) as
  taxable employment income (incl. taxable benefits and statutory pay)
  plus chargeable trading profits.
- YAML for both review cases; the property test's netted twin compares the
  earnings test and the capped award; property tests run 3 examples per
  property with larger batches to cut CI time (#2099).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With 3 generated examples per property (to keep CI time down, #2099),
a run could miss the cases that matter, and a mutant that stopped
limiting relief to net income survived. Each property now also checks
pinned inputs: relief limited by net income, both caps, contributions
above relevant earnings, no relief from age 75, profits beside a loss,
income spilling into savings and dividends, the benefit-cap household,
a child's loss and a loss beside pay.

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

This branch has not been deployed

No deployments
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.

1 participant