Skip to content

Correct the savings starting-rate taper - #2453

Merged
juaristi22 merged 1 commit into
mainfrom
fix-1799-savings-starting-rate-taper
Oct 19, 2026
Merged

juaristi22 merged 1 commit into
mainfrom
fix-1799-savings-starting-rate-taper

Conversation

@juaristi22

Copy link
Copy Markdown
Collaborator

Fixes #1799

Reduce the savings starting-rate band from the first pound of taxable non-savings income. The formula previously deducted the maximum personal allowance plus the starting-rate limit from income that already had allowances deducted, leaving the full £5,000 exemption available too far up the income range.

The correction uses the existing non-savings taxable-income aggregate, limit and phase-out parameters. It preserves property-income aggregation, personal-allowance allocation, the personal savings allowance and the remaining savings tax bands. Dividends do not directly reduce the starting-rate band; they can change personal-allowance or savings-allowance entitlement through the existing rules. The separate limit-indexation change in #2452 is independent.

The rule follows ITA 2007 s12(1) and (5), s16 income ordering, and HMRC's starting-rate guidance. Examples below use ordinary English 2026–27 inputs, the standard £12,570 personal allowance, £1,000 personal savings allowance, no other reliefs and the 20% savings basic rate:

Annual wages Savings interest Correct starting-rate band used Savings income tax Total income tax
£14,000 £6,000 £3,570 £286 £572
£30,000 £4,000 £0 £600 £4,086

For the £30,000 wages case, the original model charged £0 savings income tax. The tests use genuine annual income inputs and check final savings and total income tax, with boundaries, pensions, property, unused personal allowance, dividend-ordering and parameter-reform controls. The old five fixtures forced taxable intermediates and encoded the duplicated deduction; they are replaced by 14 meaningful cases with independently derived expected amounts.

Validation: all 75 focused tests passed (14 changed cases and 61 existing regressions; 104.59s pytest / 113.71s bounded), with per-case outcomes and JUnit recorded throughout. The final-tax-first regressions fail on unchanged production (11 failed, 3 controls passed). make format, Ruff and git diff --check pass. Local Python 3.13.14 / Core 3.32.27 differs from locked Core 3.33.2; hosted full CI remains required. Full make test, documentation build and private-data population analysis were not run for this scoped formula change.

Reproducer: policyengine_uk/tests/policy/baseline/finance/tax/income_tax/savings_starter_rate_income.yaml

axiom: needed

A rulespec-uk parity follow-up remains outstanding; no encoded-correctness or population estimate is claimed.

@vahid-ahmadi vahid-ahmadi left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks right, fine to approve.

@juaristi22, the new formula matches ITA 2007 s12 and the GOV.UK guidance. non_savings_taxable_income is already net of allowances, so each pound of it now reduces the £5,000 band once. The old code deducted the personal allowance and the band a second time.

  1. nit, policyengine_uk/variables/gov/hmrc/income_tax/bracketized_savings_income/savings_starter_rate_income.py:46 reads "ss.12(5) and16". The YAML header comments have the same missing spaces: savings_starter_rate_income.yaml lines 1, 7, 8, 11 and 210 ("rate20%", "or£500", "band£500", "future2027-28", "less50% of£1,430"). Worth tidying, because these comments are the hand-workings a reviewer reads.

What I checked

  • Read the issue, the PR body, the full diff (including all 14 YAML cases), and non_savings_taxable_income and basic_rate_savings_income_pre_starter, to confirm the base already includes property income and is net of allowances.
  • Worked two cases by hand. £14,000 wages and £6,000 interest: 1,430 taxable wages, leaving a 3,570 band; (6,000 - 3,570 - 1,000) x 20% = £286, plus wage tax £286, gives £572. £30,000 wages and £4,000 interest: no band left; (4,000 - 1,000) x 20% = £600. Both match the YAML. I also worked one case the PR body doesn't cover. With £10,000 wages and £9,000 interest, 2,570 of unused allowance leaves 6,430 of taxable interest. After the 5,000 band and 1,000 PSA, 430 x 20% = £86. This matches.
  • Ran policyengine-core test .../savings_starter_rate_income.yaml: 14 passed. With the formula reverted to main: 11 failed, 3 passed.
  • Merged this branch with #2452 locally. Both PRs' tests pass together.
  • ruff check and ruff format --check on the formula file: clean.
  • Hosted CI on 35f992c is green.
  • Process: the changelog fragment is .fixed.md; the Reproducer and axiom lines are present; the Fix evidence check is green.
  • Not checked: the rulespec-uk parity (axiom: needed), and any population-level effect.

🤖 Generated with Claude Code

@vahid-ahmadi vahid-ahmadi left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving, per my review above. The shoulds and nits can follow.

@juaristi22
juaristi22 added this pull request to the merge queue Oct 19, 2026
Merged via the queue into main with commit 5dceb94 Oct 19, 2026
14 checks passed
@juaristi22
juaristi22 deleted the fix-1799-savings-starting-rate-taper branch October 19, 2026 19:15
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.

Starting rate for savings: band is not tapered until other income exceeds £30,140; should taper from the Personal Allowance (£12,570)

2 participants