Repository navigation
Index the savings starting-rate limit after 2030–31 - #2452
Conversation
3599a30 to
eeaf911
Compare
|
Integrated main 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 |
vahid-ahmadi
left a comment
There was a problem hiding this comment.
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.
- should,
policyengine_uk/parameters/gov/hmrc/create_threshold_indexation.py:136: #2490 edits the sameINDEXED_THRESHOLDSblock and theadd_threshold_indexationbody (hunks at 124 and 307 to 370). I merged the two branches locally and they conflict increate_threshold_indexation.py. Whichever lands second needs a rebase and a rerun oftest_threshold_indexation.py. - nit,
policyengine_uk/parameters/gov/hmrc/income_tax/rates/savings_starter_rate/allowance.yaml:9: the inherited2010-04-01: 5_000is 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. - 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 4ontest_savings_starting_rate_indexation.pyandtest_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 checkandruff format --checkon 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
left a comment
There was a problem hiding this comment.
Approving, per my review above. The shoulds and nits can follow.
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 mainf1122205): 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.pyand 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.