Repository navigation
Conversation
…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>
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>
|
Heads-up from #2271 (fixes #2253), which changes how Gift Aid enters income tax. On main, Whichever of the two merges second will need to:
🤖 Generated with Claude Code |
…nual-allowance-2237
…nual-allowance-2237
|
PE-UK main fix landed (UK hub, 2026-10-11 21:42Z): #2349 merged as |
…nual-allowance-2237
Fixes #2237.
What was wrong
pension_contributions_reliefcapped relief atmax(basic amount, annual allowance), andpersonal_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
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)).capital_gains_taxalready does, the model takespersonal_pension_contributionsas relief at source andemployee_pension_contributionsas 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.capital_gains_taxdoes for the basic rate band. Net pay contributions stay deducted.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).
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:Intended deviations, documented in the test:
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/hmrcand the UC income tests pass, as do the CGT component tests.National impact
Data:
enhanced_frs_2024_25.h5@1.58.0, this branch againstmainat 6d89338 (this branch merged with it), each run as a full microsimulation (£bn, branch minus main).FY2025 decomposition (computed per person):
Notes on the figures:
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 againstmain6d89338. The construction is copied from policyengine-scorecardpipeline/build_uk_event_registry.pyon 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.
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_allowanceis 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)
adjusted_net_incomedoes not deduct relieved pension contributions (ITA 2007 s. 58), so the personal allowance taper and the High Income Child Benefit Charge ignore them. In the reproducer the personal allowance stays nil at £60,000 of contributions, though adjusted net income should be £90,000. This is separate from the double tax: Pension contributions do not reduce adjusted net income (ITA 2007 s. 58), so the personal allowance taper and HICBC ignore them #2243.pension_annual_allowancetapers on adjusted net income. It omits the s. 228ZA threshold-income test and the employer contributions that count in adjusted income, and its parameters date the taper from 2015 rather than 2016-17: Annual allowance taper ignores the s. 228ZA threshold-income test and employer contributions in adjusted income #2244.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 casesearnings_above_basic_amountandearnings_below_basic_amountin190.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