Skip to content

Index the savings starting-rate limit after 2030–31 - #2452

Merged
juaristi22 merged 1 commit into
mainfrom
fix-2431-savings-starting-rate-indexation
Oct 21, 2026
Merged

juaristi22 merged 1 commit into
mainfrom
fix-2431-savings-starting-rate-indexation

Conversation

@juaristi22

@juaristi22 juaristi22 commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #2431

Resume statutory indexation of the annual savings starting-rate limit after its freeze ends in 2030–31. The model previously kept £5,000 indefinitely. From 2031–32, the limit follows positive September CPI and rounds the resulting amount up to the next £10, starting each year from the previous rounded limit. Zero or negative CPI leaves the amount unchanged.

This implements Income Tax Act 2007 s21(3A), after the £5,000 freeze in Finance Act 2026 s9. The parameter records the frozen years and predecessor references, and its period metadata now describes an annual amount. Existing pre-2015 model values are preserved; this fix does not audit that history. The addition integrates #2423's reform-route contract from current main (f1122205) and registers the savings limit as the eighth indexed threshold. Under that contract, a finite £6,000 override for 2031–32 and assumed 2% September CPI gives a £6,120 limit in 2032–33; the CPI-only control remains £5,210. The shared helper retains main's dated-change, last-file-year and reset logic.

With assumed successive 2% September CPI rises, the limit becomes £5,100 in 2031–32, £5,210 in 2032–33 and £5,320 in 2033–34. These are test assumptions rather than known future amounts. A savings-only adult with £20,000 annual interest, the personal allowance explicitly held at £12,570, and the model's unchanged £1,000 savings allowance and 22% savings rate pays £292.60, £268.40 and £244.20 income tax respectively, compared with £314.60 while the limit is £5,000. Tests exercise final savings tax and income tax through reform dictionaries, Reform.from_dict and Scenario.

Original-head validation (3599a30a): all 20 new regressions completed within the recorded success prefix. The 191 selected test items are covered by 172 reconstructed serial successes before timeout plus 19 completed follow-up passes, with no overlap. Original new regressions failed on unchanged production (15 failed, 5 controls passed). make format, Ruff, git diff --check and the trusted-base Fix evidence check pass. The initial combined local batch reached its 540-second timeout after 172 recorded successes with no failure markers; the unfinished-only follow-up passed all 19 remaining cases (228.24s pytest / 236.58s bounded). The timed-out run has no completed-session JUnit result and is not reported as a single 191-pass session. Local Python 3.13.14 / Core 3.32.27 differs from locked Core 3.33.2. Full make test, documentation build and private-data population analysis were not run; hosted full CI remains required.

Current-head integration (eeaf911ccce8c5ce914676f79d2f634c44cfdaf5, rebased onto main f1122205): all 36 selected tests passed in one completed batch (58.11s pytest / 63.89s bounded CLI), with 0 failures, errors or skips. This covers the full 26-case savings module, 5 threshold/National Insurance/no-economic-assumptions controls and 5 dated-change/ordinary-benefit controls. The unchanged 60-example threshold property also passed within that selection. Across the three reform routes, the £6,000 override produces final savings tax and income tax of £94.60 in 2031–32 and £68.20 in 2032–33; the CPI/PA-only control pays £268.40 in 2032–33. Last-file-year, 30 April boundary and repeated-reset cases passed. Independent fix verification returned CLEAN for both scoped changes, with no new issues or material gaps. make format changed no source bytes, and all 11 executed source-file hashes match the rebased commit. Local Core 3.32.27 / Hypothesis 6.168.2 differs from locked Core 3.33.2 / Hypothesis 6.169.0. Hosted full CI for the new head remains pending; the stated full-suite, private-data and Axiom limits still apply.

Reproducer: policyengine_uk/tests/test_savings_starting_rate_indexation.py::test_indexed_starting_rate_reaches_final_savings_income_tax

Landing coordination

Landing plan: #2493, then #2452, then #2490, as requested in the #2490 review. This PR and #2490 both change create_threshold_indexation.py and its threshold-indexation tests. Preserve the savings-limit registration, dated-change/reset behavior and NI-scale indexation writers when integrating them. Actual migrations and fresh combined-tree checks remain conditions of #2490; this plan does not certify their completion.

axiom: needed

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

@juaristi22
juaristi22 force-pushed the fix-2431-savings-starting-rate-indexation branch from 3599a30 to eeaf911 Compare October 17, 2026 00:19
@juaristi22

Copy link
Copy Markdown
Collaborator Author

Integrated main f1122205 in eeaf911ccce8c5ce914676f79d2f634c44cfdaf5, retaining #2423’s dated-change/reset contract and adding savings as the eighth indexed threshold. A finite £6,000 override now resumes at £6,120 after 2% CPI, consistent with ITA 2007 s21(3A).

All 36 affected local tests passed (26 savings cases plus 10 main integration controls; 58.11s pytest / 63.89s CLI). The three reform routes reach final tax of £94.60 then £68.20, versus the £268.40 CPI/PA-only control. Independent fix verification returned CLEAN. Hosted full CI for this new head remains pending; local Core 3.32.27 differs from locked 3.33.2, and axiom: needed remains.

@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 indexation matches ITA 2007 s21(1) and (3A). The base is the previous year's limit, the CPI rise must be positive, and the result rounds up to a multiple of £10. FA 2026 s9(2) disapplies s21 for 2026-27 to 2030-31, so 2031-32 is the first indexed year. The period: week metadata fix is also right.

  1. should, policyengine_uk/parameters/gov/hmrc/create_threshold_indexation.py:136: #2490 edits the same INDEXED_THRESHOLDS block and the add_threshold_indexation body (hunks at 124 and 307 to 370). I merged the two branches locally and they conflict in create_threshold_indexation.py. Whichever lands second needs a rebase and a rerun of test_threshold_indexation.py.
  2. nit, policyengine_uk/parameters/gov/hmrc/income_tax/rates/savings_starter_rate/allowance.yaml:9: the inherited 2010-04-01: 5_000 is wrong for 2010-11 to 2014-15. The limit was below £5,000 until 2015-16. The model starts in 2015, so nothing changes, and the PR body is clear that this history is out of scope. A one-line follow-up issue would stop it being trusted later.
  3. nit: the PR body says "hosted full CI for the new head remains pending". It has now passed on eeaf911.

What I checked

  • Read s21 and FA 2026 s9 on legislation.gov.uk, including the s21 exclusion annotations for 2015-16 to 2030-31.
  • Worked the rounding by hand: 5,000 x 1.02 = 5,100; 5,100 x 1.02 = 5,202, which rounds up to 5,210; 5,210 x 1.02 = 5,314.20, which rounds up to 5,320. Worked the £20,000 interest case: 7,430 taxable, less 5,100 starting band and 1,000 PSA, leaves 1,330 x 22% = £292.60.
  • Ran pytest -n 4 on test_savings_starting_rate_indexation.py and test_threshold_indexation.py: 113 passed.
  • Merged this branch with #2453 locally. The savings indexation tests (26) and #2453's starter-rate YAML (14) all pass together.
  • ruff check and ruff format --check on the three changed Python files: clean.
  • Merged this branch with #2490 locally: conflict in create_threshold_indexation.py.
  • Process: the changelog fragment is .fixed.md; the Reproducer and axiom lines are present; the Fix evidence check is green.
  • Not checked: the pre-2015 limits, the rulespec-uk parity follow-up, and the earlier revert-and-fail run (I relied on the PR's account).

🤖 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 21, 2026
Merged via the queue into main with commit b3d5718 Oct 21, 2026
16 checks passed
@juaristi22
juaristi22 deleted the fix-2431-savings-starting-rate-indexation branch October 21, 2026 10: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.

Index the starting rate limit for savings from 2031-32 (ITA 2007 s21(3A))

2 participants