Skip to content

Charge Class 4 NI on full trading profits, without deducting Class 1 - #1886

Merged
MaxGhenis merged 2 commits into
mainfrom
class-4-profits-no-class-1-deduction
Sep 27, 2026
Merged

MaxGhenis merged 2 commits into
mainfrom
class-4-profits-no-class-1-deduction

Conversation

@MaxGhenis

Copy link
Copy Markdown
Collaborator

Fixes #1885

What was wrong

ni_class_4 and ni_class_4_main computed Class 4 profits as self_employment_income - ni_class_1_employee. Trading profits were reduced by the person's employee Class 1 NI before the Lower and Upper Profits Limits applied.

The law has no such deduction. SSCBA 1992 Sch 2 para 2 charges Class 4 on "the full amount of all profits" chargeable under ITTOIA 2005 Part 2 Ch 2. The only reliefs are those in para 3: trade losses under ITA 2007 ss.64, 72, 83 and 89, and the interest and annual payments in para 3(5). Class 1 contributions are not among them. The Class 1 / Class 4 interaction is handled solely by the regulation 100 annual maximum. The model already implements that in ni_class_4_maximum, and its Steps Six and Nine already used undeducted profits. The deduction arrived with a 2021 validation commit (66b6dce) with no comment or reference. The only Class-1-related exclusion in law is reg 94 of the 2001 Regulations (NIM24620). It removes earnings that bear Class 1 but are taxed as trading income, on application; it does not remove Class 1 contributions. It can't arise here, because employment_income and self_employment_income are separate inputs.

Example (2026-27): employment £30,000 and profits £20,000. The statute gives 6% × (20,000 − 12,570) = £445.80, and the annual maximum does not bind. The model returned about £362.

Changes

  • ni_class_4, ni_class_4_main: Class 4 profits are self_employment_income.
  • ni_class_4_maximum: the Case 1 unused-band test (from Fix Class 4 NI dropping the additional-rate band at non-round thresholds #1884) uses the same profits.
  • ni_class_4 gets its own label ("NI Class 4 contributions", previously a copy of ni_class_4_main's) and a s.15 reference.
  • Tests:
  • Docs: the NI notebook's Class 4 row no longer says "self-employment income minus Class 1 employee NI". The saved table output is regenerated to match, since docs builds don't execute notebooks.

Invariants

These hold for any 0 ≤ LPL < UPL, rates ≥ 0 and profits ≥ 0. Comparisons allow float32 storage: 1p + 4×10⁻⁷ × the largest amount involved.

  1. Statute when the maximum does not bind. Whenever reg 100 does not apply (no primary Class 1 or Class 2) or its maximum is at least the s.15(3) amount, ni_class_4 = main × clamp(p − LPL, 0, UPL − LPL) + additional × max(p − UPL, 0), with p the full self-employment profit.
  2. Differential. For everyone, ni_class_4 equals an exact-rational implementation of s.15(3) capped by the literal reg 100 steps.
  3. Bounds. 0 ≤ ni_class_4 ≤ the s.15(3) amount.
  4. Monotonicity. With employment income fixed, ni_class_4 is non-decreasing in profits wherever Class 2 does not change. Before April 2024, reg 100 subtracts Class 2, so crossing the small profits threshold can lower Class 4; Class 2 + Class 4 stays non-decreasing when main ≥ additional.
  5. Scope of change. Only people with employee Class 1 NI can change, and their Class 4 can only rise. For fixed Class 2 (unchanged here, since it depends on undeducted income both before and after), the pre-maximum amount and the maximum are both non-decreasing in the Class 4 profit base, and this change only raises that base.

Verification

Self-employment × employment grid: 1,732 profit levels (£0–£300k) × 152 employment incomes (£0–£150k), 263,264 cells per year. Base is #1884's merged code (2.102.1), head is this PR.

Year Cells changed Changed without Class 1 Decreases Mean increase (changed cells) Max increase
2023 9,955 0 0 £102.66 £282.52
2026 7,144 0 0 £41.16 £125.56
2028 7,480 0 0 £42.03 £129.12
2030 7,714 0 0 £44.04 £135.85

In every year, each cell where the maximum does not bind equals the closed-form statute on full profits. Cells where the maximum binds, which is most dual earners with profits well above the LPL, are unchanged. 2023 is larger because of that year's 9% main rate.

Aggregate revenue effect on the FRS-based microsimulation: not computed locally, since the dataset needs credentials. CI's microsimulation tests run on it.

Axiom parity

axiom: uk:statutes/ukpga/1992/4/15 encoded-correct (TheAxiomFoundation/rulespec-uk uk/statutes/ukpga/1992/4/15.yaml charges profits_chargeable_to_class_4_contributions with no Class 1 deduction; companion test 15.test.yaml::class_4_main_and_additional_contributions_apply)

The Axiom-vs-policyengine-uk NICs grid in TheAxiomFoundation/axiom-oracles#565 attributes 4 dual-earner rows to #1885.

Independent review

Claude Opus 5.5 via Subfleet (read-only) returned APPROVE with nothing blocking:

  • It confirmed the legal claim from SSCBA Sch 2 paras 2–3, reg 100 and reg 94 / NIM24620.
  • It found no other profit deduction in the model code.
  • It proved the "only Class 1 payers, only upward" invariant, and reproduced the £445.80 / £362.14 example by hand.

Its notes are addressed in this PR: the stale saved notebook output, the monotonicity caveat, the Axiom repo path, the reg 94 note and the duplicated ni_class_4 label.

Commands run

  • ruff format . and ruff check .
  • pytest policyengine_uk/tests/test_ni_class_4_maximum.py policyengine_uk/tests/test_ni_class_4_properties.py policyengine_uk/tests/test_parameter_descriptions.py (16 passed)
  • policyengine-core test policyengine_uk/tests/policy/baseline/gov/hmrc/national_insurance -c policyengine_uk (38 passed)
  • A 300-random-example (non-derandomised) Hypothesis campaign per property, with the model pinned to this branch: both passed.

🤖 Generated with Claude Code

MaxGhenis and others added 2 commits September 27, 2026 09:09
SSCBA 1992 Sch 2 para 2 charges Class 4 on the full amount of trading
profits; the para 3 reliefs do not include Class 1 contributions. The
interaction with Class 1 is handled by the regulation 100 annual maximum.

Fixes #1885

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ni_class_4 is total Class 4, not main-rate Class 4, so give it its own
label and a section 15 reference. The docs do not execute notebooks, so
regenerate the Class table output to match its source.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis
MaxGhenis marked this pull request as ready for review September 27, 2026 13:36
@MaxGhenis
MaxGhenis merged commit 6393f1e into main Sep 27, 2026
7 checks passed
@MaxGhenis
MaxGhenis deleted the class-4-profits-no-class-1-deduction branch September 27, 2026 13:38
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.

Class 4 NI deducts employee Class 1 NI from trading profits, which the law does not allow

1 participant