Repository navigation
Uprate additional State Pension and protected payments by September CPI - #2336
Conversation
The part of a reported State Pension above the type's full rate (additional pension for the basic State Pension, protected payments for the new) was uprated by the full rate's own triple-lock rise. Each Up-rating Order raises it by September CPI instead (SSAA 1992 ss.150(1)(c), 151 and 151A; SI 2026/148 arts 4(3) and 6(3)(b): 3.8% against 4.8% for the full rates; SI 2025/295: 1.7% against 4.1%). Uprate it by gov.economic_assumptions.indices.september_cpi_uprating from the data year, read from the simulation's own parameters, so a reform to the full rates or the triple lock no longer moves it and a price scenario does. Fixes #1941. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rms as a reform CI found two test faults (run 38161065391): the differential against main's formula compared the model's float32 arrays with a float64 reference at rtol 1e-12, which fails for any reported amount float32 cannot hold exactly (e.g. £169.00 a week, aged 98); and a Scenario cannot take the reform dictionary's "2026-01-01.2100-12-31" period, so that case passes it as a reform. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…in the docs At 5% September CPI the triple lock also rose 5%, so the scenario test passed on main. At 1%, below the triple lock's 2.5% floor, the add-on rises 1% and the full rates at least 2.5%. The docs record the change in the model's State Pension against DWP's forecast, from full runs on the certified dataset. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keep the September CPI uprating in additional_state_pension: main's np.divide guard (00c07d6) was on the full-rate ratio this branch replaces. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…branch Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: GPT-6 <noreply@openai.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… into the age addition branch Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…oor and two simplifications From the independent review of 4e495b7: the 17.0% per-recipient growth came from runs before this fix; from April 2027 SSAA 1992 ss.150(2) and 151A(3) set a floor ("not less than" the rise in prices) that the model pays exactly; contracted-out records and additional pension inside a partial basic pension are simplified. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…branch Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Aggregate impact on certified data: passBase Checks: 0 broken by this change, 1 failing on both sides, 0 fixed. Moves flagged for review: 97 (thresholds in Notes
Moves flagged for review
57 more flags are in the report artifact. Receipts by tax head
Spending by benefit and service
Caseloads
Government balance, each component counted once
Model totals
Household income totals
Poverty rates
People in poverty
Inequality
Mean household net income in each side's own deciles
Standard reform costings (change in gov_balance)
Standard reforms: change in each reform's target
Household net income by decileMean change in household net income per household, and as a share of the decile's base income; households stay in the base run's deciles.
No change in any year: components the model counts twice; population. Checks failing on both base and head (1)
Counted-once checkEach of 84 components was raised by £1 per unit in 2026-27, and every head of its totals was read household by household: its own head must rise by exactly £1, no other tax head may move, no other benefit may rise, and the model's own total must move by what its heads moved. A head that breaks a rule is measured again twice: with every other head held at its baseline value, and with every other head held at its value after the first £1 while the component rises again. It fails where either still shows the response. 0 failed; 0 were skipped.
Provenance
Dataset: Receipts by tax head: head levels
Spending by benefit and service: head levels
Caseloads: head levels
Government balance, each component counted once: head levels
Model totals: head levels
Components the model counts twice: head levels
Household income totals: head levels
Population: head levels
Poverty rates: head levels
People in poverty: head levels
Inequality: head levels
Mean household net income in each side's own deciles: head levels
Standard reform costings (change in gov_balance): head levels
Standard reforms: change in each reform's target: head levels
|
|
Hand-off to the UK hub (W7, session local_94f3ee40).
🤖 Generated with Claude Code |
|
Merged by the UK hub (session local_8e19f9d5, Opus 5.5) on its merge gates, as
🤖 Generated with Claude Code |
Fixes #1941
Additional pensions (SERPS/S2P) and new State Pension protected payments rise each April by September CPI. The model raised them by the full rate's own triple-lock ratio. This uprates them by September CPI from the data year, as the Up-rating Orders do.
Law
Additional pensions and protected payments follow prices separately from the full State Pension rates. SI 2026/148 article 4(3) directs the covered additional pensions to be “increased by 3.8 per cent.”, with a final relevant year before 2025–26. Article 6(3)(b) covers amounts “at the transitional rate which exceed the full rate” and applies the same 3.8%. The full rates rise about 4.8%: £176.45→£184.90 and £230.25→£241.30 (articles 4(2) and 6(1)).
The equivalent 2025 article 4(3) and article 6(3)(b) direct the add-ons to be “increased by 1.7 per cent.”, against about 4.1% for the full rates. The made HTML and XML were read for both Orders; the current 2025
/data.xmlomits these provisions, so the operative text was checked at/made/data.xml.SSAA 1992 sections 150–151 provide the prices review and percentage increase for additional pensions; section 151A covers the transitional excess. These duties prescribe an increase when prices rise, rather than a cut when they fall. The 2016 Order explanatory memorandum, paragraph 4.2 and footnote 2, confirms no increase under section 150 when September 2015 CPI was −0.1%. Section 150A sets an earnings minimum for the full rates; it does not itself legislate all three triple-lock elements.
Change
additional_state_pensionuprates the reported excess above the period type's legislated data-year full rate byI(period) / I(data_year), whereIis the simulation's owngov.economic_assumptions.indices.september_cpi_uprating. CPI or macro scenarios can therefore move the add-on. The baseline data-year split from #2122 remains; basic and new flat-rate components retain their full-rate ratios.Reforms to the full rates or the triple lock no longer move the add-on, because in law it follows prices (SI 2026/148 articles 4(3) and 6(3)(b)). For the years the Up-rating Orders cover (to April 2026) the model reproduces each Order's percentage exactly. From April 2027 SSAA 1992 ss.150(2) and 151A(3) set a floor ("not less than" the rise in prices); the model pays exactly September CPI, the floor and what every Order has given. A reform that raises the add-on by more would need a reform to this variable. This intentionally changes the #2122 full-rate-reform expectations, including a rate of zero.
gov.contrib.abolish_state_pensionstill removes the entire pension.The existing September CPI builder was read, including its docstring: published September CPI is rounded to 0.1 percentage points and floored at zero. The test reference hard-codes the statutory rises for 2011–2026 and independently rounds CPI inputs only for forecast years; it never calls the production index. Those historical percentages were checked against the Orders, including zero in April 2016. The model rounds each compounded index to five decimal places, so ratio/reference checks allow
1e-5rounding tolerance.Files:
policyengine_uk/variables/gov/dwp/additional_state_pension.py(the add-on's uprating),policyengine_uk/tests/test_state_pension_components.py(statutory reference, dataset-built regressions, properties),docs/book/programs/gov/dwp/state-pension.md(Components, Uprating, the forecast-year floor, one remaining simplification, What's been fixed),changelog.d/1941.fixed.md.Tests and fail-on-main evidence
Dataset-built cases (the YAML runner has no dataset, so its data year is the period and it cannot show uprating): a basic pensioner reporting £200 a week in 2024-25 has 2026-27 additional pension (200 − 169.50) × 52 × 1.017 × 1.038 = £1,674.25; a new State Pension recipient reporting £240 has a 2026-27 protected payment (240 − 221.20) × 52 × 1.017 × 1.038 = £1,032.00; and the add-on grows each year by that year's September CPI rise. The independent review recomputed both by hand.
Fail on main, pass on head.
policyengine_uk/tests/test_state_pension_components.pyfrom this head, copied into a detached tree at main76cfc9e79: 23 failed, 8 passed (16 min,-n 4). Every failure is an assertion showing main's flat-rate uprating, for example an add-on ratio of 1.0410 (176.45 / 169.50) where the 2025 Order gives 1.017. The 8 passes are the cases this PR doesn't change. At2fd0c7a8the same file passed 31/31; since then only merges of main and docs changed, and CI runs the full suite on this head.Invariants and mutation evidence
Four Hypothesis tests, ten deterministic examples each, cover:
All four properties were also reduced to one initial BASIC record (male, age 90, three months since birthday, £200/week in 2024): 4 expected failures on main in 7.33 seconds; 4 passes on head in 6.98 seconds. The monotonicity case adds the required paired record reporting £1/week more; the reform case sets both full rates to zero, undated. Main's deflated accounting result is £10,437.43275 against a £10,400 report, and its zero-rate reform removes £1,586 of data-year add-on; the fix preserves both identities. These are synthetic counterexamples, not national figures.
The saved mutation run had 12/12 unmutated checks pass and 5/5 mutants killed: restore full-rate uprating; read CPI from baseline instead of the scenario; remove the floor; use the prior-year index; split at the reformed data-year full rate. This evidence predates the main merges; its formula source is identical to the merged formula head. A fresh scratch-tree confirmation passed three unmutated statutory/scenario controls, then killed both restored full-rate uprating (one intended assertion failure) and baseline-CPI reading (one intended assertion failure). The source was restored and the scratch clone removed. Each command used
uv run --active --no-sync pytest <selected nodeids> -n 0 -vv --tb=short -o usefixtures=cloned_uk_tax_benefit_system; no model file was mutated in the actual head.Impact on the certified pair
Real
Microsimulationruns, one per code version and year, onenhanced_frs_2024_25.h5from policyengine-uk-data 1.58.1 (sha256056e80fd8e91…, the dataset in policyengine.py's certified UK bundle, pe-uk 2.130.1 + uk-data 1.58.1). Base: main76cfc9e79. Head: this PR atfa27e4948. Both trees clean. About 10 s a year each.additional_state_pensionstate_pensionpension_credithousing_benefituniversal_creditcouncil_tax_reductionincome_taxhousehold_net_incomegov_balanceadditional_state_pension 2030-31: base £12,616.6m, head £11,834.7m, records changed 14600, weighted 5,543,341
state_pension 2030-31: base £138,021.6m, head £137,239.7m, records changed 14600, weighted 5,543,341
Disclosure: any cell resting on fewer than three dataset records is shown as
–, with complementary suppression. Scripts:run_impact.pyandcompare.py(kept with the evidence, outside the repo).Overlaps
docs/book/programs/gov/dwp/state-pension.mdandcreate_triple_lock.py; expect a text conflict in the docs page.additional_state_pensionper person withset_input, so this formula doesn't run in its simulations; that project has been told, and the variable name andset_inputbehaviour are unchanged.Review
GPT-6.1 Sol reviewed
4e495b77e(APPROVE on law and code) and then this head,fa27e4948(APPROVE). The first review's P2 findings (stale body, a pre-fix figure in the docs, a wrong overlap note) and P3 notes (the forecast-year floor, a stated simplification) are addressed; the second review's two wording notes are in this body. The commits after the first review change onlydocs/book/programs/gov/dwp/state-pension.md.Axiom parity
axiom: TheAxiomFoundation/rulespec-uk#457 queued
Reproducer:
policyengine_uk/tests/test_state_pension_components.py::test_additional_pension_rises_with_september_cpi_not_the_basic_rate,policyengine_uk/tests/test_state_pension_components.py::test_protected_payment_rises_with_september_cpi_not_the_new_rate,policyengine_uk/tests/test_state_pension_components.py::test_add_on_grows_each_year_by_that_years_september_cpi_rise🤖 Generated with Claude Code