Repository navigation
Correct the savings starting-rate taper - #2453
Merged
Merged
Conversation
vahid-ahmadi
left a comment
Collaborator
There was a problem hiding this comment.
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.
- nit,
policyengine_uk/variables/gov/hmrc/income_tax/bracketized_savings_income/savings_starter_rate_income.py:46reads "ss.12(5) and16". The YAML header comments have the same missing spaces:savings_starter_rate_income.yamllines 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_incomeandbasic_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 checkandruff format --checkon 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
approved these changes
Oct 18, 2026
vahid-ahmadi
left a comment
Collaborator
There was a problem hiding this comment.
Approving, per my review above. The shoulds and nits can follow.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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:
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.