Skip to content

Relieve pension contributions to relevant earnings and charge the annual allowance excess once - #2240

Open
MaxGhenis wants to merge 6 commits into
mainfrom
fix-pension-relief-annual-allowance-2237
Open

MaxGhenis wants to merge 6 commits into
mainfrom
fix-pension-relief-annual-allowance-2237

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 10, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #2237.

What was wrong

pension_contributions_relief capped relief at max(basic amount, annual allowance), and personal_pension_contributions_tax (the annual allowance charge) also charged the pension input amount above the allowance. Contributions above the allowance were denied relief and charged, so the excess was taxed twice. The issue's reproducer: £150,000 earnings, London, 2024. £80,000 of contributions cost £8,000 more income tax than £60,000 (£36,460 against £28,460).

The law

  • Finance Act 2004 s. 190. Relief runs up to the individual's relevant UK earnings chargeable to income tax, raised to the basic amount (£3,600) where earnings are lower. s. 191(7): only relief at source can give that increase. The annual allowance does not limit relief.
  • s. 227(1), 227ZA(3). The annual allowance charge is on the pension input amount above the annual allowance.
  • s. 227(4A)-(4C). It is charged at the basic, higher and additional rates on the slices of the chargeable amount that fall in each band when it is added to the individual's reduced net income (income after allowances, ITA 2007 s. 23 Step 3). The rate limits are those raised by relief-at-source contributions (s. 192) and grossed-up Gift Aid (ITA 2007 s. 414).
  • s. 227(4AA). A Scottish taxpayer pays the Scottish rates, with the Scottish basic rate on any slice up to the Scottish basic rate limit (so never the starter rate).
  • s. 228A. Unused allowance from the three previous years increases this year's allowance.

Changes

  • pension_contributions_relief: contributions up to relevant UK earnings, plus up to the shortfall below £3,600 from relief-at-source contributions only (s. 191(7)), for anyone under 75 (s. 188(3)(a)). Relevant UK earnings are employment income plus trading profits; a trading loss no longer reduces employment income (s. 189(2)).
  • Assumption, declared. As capital_gains_tax already does, the model takes personal_pension_contributions as relief at source and employee_pension_contributions as a net pay arrangement. Some workplace schemes use relief at source for employee contributions. Treating those as net pay gives them no £3,600 increase and no rate-limit extension, the conservative side. Sensitivity, computed: treating all employee contributions as relief at source instead would change income tax by −£1.1m to −£1.3m a year (2025-2030) and the charge by £0.
  • pension_annual_allowance_chargeable_amount (new): pension input amount less the annual allowance and any unused allowance brought forward.
  • unused_pension_annual_allowance (new input, nil by default): unused allowance carried forward under s. 228A. Survey data records no past pension input amounts, so the national figures assume none. Household users can enter it.
  • personal_pension_contributions_tax: band-by-band top slice of reduced net income, using the UK scale or, for Scottish taxpayers, the Scottish scale with the starter band charged at the Scottish basic rate.
    • The model deducts relief at source and Gift Aid from income, so the formula adds them back to reach statutory reduced net income. It then raises every rate limit by the relieved relief-at-source contributions plus grossed-up Gift Aid, as capital_gains_tax does for the basic rate band. Net pay contributions stay deducted.
    • The starter band is recognised only when the raw starter bracket has both a rate and a threshold, so a reform that removes it is followed.
    • The charge previously took the whole excess at the marginal rate at taxed_income. That understated the charge when the excess crossed into a higher band. It also left property income and income within the dividend allowance out of the stacking point. The label now says what the variable is.

Tests

Examples (YAML).

  • The issue's reproducer: £60,000 and £80,000 of contributions both give £28,460 of income tax. The £80,000 case has £80,000 of relief and an £8,000 charge.
  • Net pay: a charge that spans the basic and higher bands (£7,540 + £920).
  • Relief at source: the same inputs give £8,000, because the basic rate limit rises to £97,700 (review case; HMRC PTM056120).
  • Gift Aid raises the limits by its grossed-up amount (£3,696).
  • A Scottish taxpayer in the advanced band.
  • A Scottish starter-band case (20%, not 19%, on the starter band).
  • Full and partial carry-forward.
  • The s. 190(2) basic amount: relief at source can fill it, a net pay arrangement cannot (s. 191(7)). Also the earnings cap, a trading loss, and no relief at 75.
  • A documented model deviation for Scotland (below).

Properties (test_pension_annual_allowance_properties.py, Hypothesis, populations of single adults across 2020, 2024, 2026 and 2027 and four regions, with contributions split between relief at source and net pay, and Gift Aid). Invariants:

  1. Relief equals contributions up to earnings plus the relief-at-source part of the £3,600 increase, under 75, and nil at 75 or over. Compared at float32 precision.
  2. Raising contributions, up to relevant earnings, never raises income tax by more than it raises the charge.
  3. For someone outside Scotland whose income is all non-savings income, contributing above the allowance, up to relevant earnings and taxable income, never costs more income tax than contributing exactly the allowance. This is the "no double tax" property.
  4. The charge is nil exactly when the chargeable amount is nil, and lies between the lowest and highest rate charged times the chargeable amount.
  5. Differential: the charge equals an independent band-by-band sum over the rate scale, with the limits raised by relief at source and grossed-up Gift Aid.
  6. Unused allowance reduces the chargeable amount one for one and never raises the charge.

Intended deviations, documented in the test:

  • With dividends on top of non-savings income, invariant 3 can fail by statute. Relief comes off non-savings income and lets dividends fall to lower dividend rates, while s. 227(4A) charges the excess at the non-savings rates.
  • Contributions beyond income after allowances get no relief but are still charged. s. 227 charges the input amount, relieved or not.
  • Scotland (a model deviation, not the statute). The model gives relief at source as a deduction, so a Scottish starter-rate slice is relieved at 19%, while relief at source pays 20% and s. 227(4AA) charges that slice at the Scottish basic rate. Contributing beyond the allowance can therefore cost up to 1% of the starter band (£39.67 in the YAML example). The property excludes Scotland and the YAML pins the deviation.

Mutation check. With the old AA-capped relief restored, the s. 190 property and the no-double-tax property both fail with falsifying examples. The starter-band reform regression fails on this PR's first head.

Targeted suites. 816 YAML tests under gov/hmrc and the UC income tests pass, as do the CGT component tests.

National impact

Data: enhanced_frs_2024_25.h5@1.58.0, this branch against main at 6d89338 (this branch merged with it), each run as a full microsimulation (£bn, branch minus main).

2025 2026 2027 2028 2029 2030
income tax −0.055 −0.042 −0.031 −0.237 −0.354 −0.457
of which annual allowance charge +0.146 +0.181 +0.213 +0.021 +0.021 +0.022
pension contributions relief +0.951 +1.012 +1.057 +1.100 +1.368 +1.609
gov balance −0.055 −0.042 −0.031 −0.237 −0.354 −0.457

FY2025 decomposition (computed per person):

relief income tax people
Contributions above the allowance now relieved (the double tax removed) +£0.238bn −£0.107bn 17k
Relief at source up to £3,600 where relevant earnings are lower (s. 190(2), 191(7)); previously capped at earnings +£0.712bn −£0.093bn 388k (213k with a tax change)
Charge now top-sliced across bands, relief unchanged — +£0.146bn 88k

Notes on the figures:

  • The 88k with higher tax are people whose input amount is mostly employer contributions and whose excess crosses into a higher band. s. 227(4A) charges those slices at the higher rate, where the old code used the rate at the bottom of the slice.
  • From 2028 the charge rises less against main. Main's single-marginal-rate charge jumps 12% in 2028 (£4.17bn to £4.67bn), against 7% for the top-sliced charge (£4.38bn to £4.69bn). The relief effect is about −£0.20bn to −£0.26bn of tax a year in 2025-2028, rising to −£0.37bn in 2029 and −£0.48bn in 2030 as contributions grow.
  • The 2029 rise in relief in both runs is the April 2029 salary-sacrifice cap moving sacrifice into employee contributions.
  • No carry-forward is assumed. The input lets data or users supply it.

Fiscal-event replay: Spring Budget 2023 Annual Allowance increase

Real microsimulation runs of the replay construction on the proposed certified data (enhanced_frs_2024_25.h5@1.58.0), this branch against main 6d89338. The construction is copied from policyengine-scorecard pipeline/build_uk_event_registry.py on main, snapshotted 2026-10-11 (event_replay.py). Gain to the Exchequer, £bn.

Reversal: restore the £40,000 allowance, £4,000 tapered minimum and £240,000 taper.

income tax 2024 2025 2026 2027 2028 2029 2030
main +2.781 +3.047 +3.278 +3.450 +3.603 +3.733 +3.750
this PR +2.698 +2.817 +2.918 +3.005 +3.056 +3.116 +3.190

Removing the double tax lowers the measure's modelled cost by £0.08bn (2024) to £0.56bn (2030). The rest of the gap to the OBR's £0.2bn to £0.4bn is the construction scope #2237 names. There is no carry-forward data: unused_pension_annual_allowance is nil, an input. The input amount also counts all employer contributions, which #2237 notes stand in for defined-benefit accrual. Both are outside this fix. NICs: no effect. Input support: the measure reads only existing inputs (pension contributions, employer contributions, income), so the national exposure is not inert.

Not in this PR (found while fixing it)

Overlaps

The fiscal-event replay (PolicyEngine/policyengine-scorecard#157) reverses Spring Budget 2023's allowance increase on the certified world. With relief no longer capped at the allowance, that reversal no longer costs the double-taxed excess.

axiom: uk/statutes/ukpga/2004/12/190 encoded-correct (rulespec-uk 190.yaml, maximum_relief_under_section_188 = max(relevant earnings, 3600); companion cases earnings_above_basic_amount and earnings_below_basic_amount in 190.test.yaml) | TheAxiomFoundation/rulespec-uk#444 queued (FA 2004 s. 227 charge with s. 227ZA default chargeable amount, and s. 228A carry-forward; blocked on corpus ingest of those sections)

🤖 Generated with Claude Code

Reproducer: policyengine_uk/tests/policy/baseline/gov/hmrc/pensions/pension_contributions_relief.yaml, policyengine_uk/tests/policy/baseline/gov/hmrc/pensions/personal_pension_contributions_tax.yaml, policyengine_uk/tests/test_pension_annual_allowance_properties.py::test_relief_is_the_section_190_limit, policyengine_uk/tests/test_pension_annual_allowance_properties.py::test_extra_contributions_never_raise_tax_by_more_than_the_charge, policyengine_uk/tests/test_pension_annual_allowance_properties.py::test_contributions_above_the_allowance_are_not_taxed_twice, policyengine_uk/tests/test_pension_annual_allowance_properties.py::test_charge_matches_band_by_band_reference

…ess once

pension_contributions_relief capped relief at the annual allowance, and
personal_pension_contributions_tax also charged the excess over it, so
contributions above the allowance were taxed twice. Relief now runs to the
s. 190 limit (the greater of relevant UK earnings and £3,600), and the annual
allowance charge recovers it once.

The charge now taxes the chargeable amount as the top slice of reduced net
income at the basic, higher and additional rates (FA 2004 s. 227(4A)), or the
Scottish rates with the starter band at the Scottish basic rate (s. 227(4AA)),
instead of one marginal rate. Unused allowance carried forward (s. 228A) is a
new input, nil by default.

Fixes #2237

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 2 commits October 10, 2026 08:07
Review round 1 on #2240:
- The annual allowance charge now stacks the chargeable amount on statutory
  reduced net income and raises every rate limit by relieved relief-at-source
  contributions and grossed-up Gift Aid (FA 2004 s. 227(4C)). Translating the
  model's deductions and flooring at zero lost the extension once
  relief-at-source contributions passed income after allowances (£8,460
  charged where the statute gives £8,000).
- Only relief at source can give the increase to the £3,600 basic amount
  (s. 191(7)); personal contributions are taken as relief at source, employee
  contributions as net pay, as capital_gains_tax does.
- Recognise the Scottish starter band only when the raw bracket has both a
  rate and a threshold.
- Property tests cover both relief methods and Gift Aid, use float32-aware
  tolerances, and exclude Scotland from the no-double-tax property; a YAML
  example pins the Scottish deviation from relieving relief at source by
  deduction.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review round 2 on #2240: the upper and lower charge bounds now allow the same
relative float32 error as the other assertions.

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

Copy link
Copy Markdown
Collaborator Author

Heads-up from #2271 (fixes #2253), which changes how Gift Aid enters income tax.

On main, allowances includes gift_aid, so income tax deducts the net donation from taxable income; this PR's allowances_at_step_3 adds Gift Aid back for that reason. #2271 removes that deduction: under ITA 2007 s.414(2) the relief is only the rate-limit increase by the grossed-up gift, and s.58 step 2 deducts the grossed-up gift from adjusted net income. It adds net_income (income before the s.58 gift deduction) and moves readers that used adjusted_net_income as a taxable base onto it.

Whichever of the two merges second will need to:

  • remove - gift_aid from allowances_at_step_3, keeping the relief-at-source subtraction;
  • compute reduced_net_income from net_income (or restore the grossed-up gift before that step), since adjusted_net_income will already have the gift deducted;
  • keep rate_limit_extension = gift_aid_grossed_up + relief_at_source;
  • update the reference and no-double-tax calculations in test_pension_annual_allowance_properties.py and the PR wording.

🤖 Generated with Claude Code

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

PE-UK main fix landed (UK hub, 2026-10-11 21:42Z): #2349 merged as ed7b42f9. It fixes test_dataframe_dataset.py::test_an_exported_frame_loads_back_and_exports_itself, which failed on every PR after #2251. Merge main into this branch and push once; don't re-run an old run, because re-runs use the original commit. If this PR's only Test failure was that test, the next run should be green.

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.

Pension contributions above the Annual Allowance are denied relief and also charged the Annual Allowance charge

1 participant