Skip to content

Commit a22ba6c

Browse files
vahid-ahmadiclaude
andauthored
Align triple lock with published DWP / OBR uprating rates (#953) (#1635)
The previous triple lock formula computed each year's uprating from calendar-year OBR average earnings, but DWP actually uses May-July AWE growth, leaving every year off by 0.5-1.2pp. Override the formula with published outturn rates for 2022-2026 and correct the hard-coded April 2025 basic and new state pension amounts (£176.45 / £230.25) plus add April 2026 (£184.90 / £241.30). Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 858fff8 commit a22ba6c

6 files changed

Lines changed: 107 additions & 12 deletions

File tree

changelog.d/953.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Align state pension triple lock with published outturn rates so basic and new state pension amounts match DWP / OBR figures for 2025-26 and 2026-27 instead of being ~1% off.

policyengine_uk/parameters/gov/dwp/state_pension/basic_state_pension/amount.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ values:
2323
2022-01-01: 141.85
2424
2023-01-01: 156.2
2525
2024-01-01: 169.5
26-
2025-04-01: 172.38
26+
2025-04-01: 176.45
27+
2026-04-01: 184.9
2728
metadata:
2829
unit: currency-GBP
2930
label: Basic State Pension amount

policyengine_uk/parameters/gov/dwp/state_pension/new_state_pension/amount.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ values:
99
2022-01-01: 185.15
1010
2023-01-01: 203.85
1111
2024-01-01: 221.2
12-
2025-04-01: 224.96
12+
2025-04-01: 230.25
13+
2026-04-01: 241.3
1314
metadata:
1415
unit: currency-GBP
1516
label: New State Pension amount

policyengine_uk/parameters/gov/dwp/state_pension/triple_lock/create_triple_lock.py

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,30 @@ def add_triple_lock(parameters: ParameterNode) -> ParameterNode:
1313
cpi = obr.consumer_price_index
1414
triple_lock = parameters.gov.dwp.state_pension.triple_lock
1515
min_rate = triple_lock.minimum_rate
16+
# Years with a published outturn or DWP-announced rate to use directly
17+
# instead of the formula (the formula relies on OBR calendar-year averages,
18+
# which don't match the May-July AWE window DWP actually uses).
19+
outturn_years = {int(v.instant_str[:4]) for v in triple_lock.outturn.values_list}
1620

1721
values = {}
1822

1923
for year in YEARS:
20-
earnings_increase = average_earnings(year - 1)
21-
cpi_increase = cpi(year - 1)
22-
min_rate_y = min_rate(year)
23-
if triple_lock.include_earnings(year) and triple_lock.include_inflation(year):
24-
triple_lock_increase = max(earnings_increase, cpi_increase, min_rate_y)
25-
elif triple_lock.include_earnings(year):
26-
triple_lock_increase = max(earnings_increase, min_rate_y)
27-
elif triple_lock.include_inflation(year):
28-
triple_lock_increase = max(cpi_increase, min_rate_y)
24+
if year in outturn_years:
25+
triple_lock_increase = triple_lock.outturn(year)
2926
else:
30-
triple_lock_increase = min_rate_y
27+
earnings_increase = average_earnings(year - 1)
28+
cpi_increase = cpi(year - 1)
29+
min_rate_y = min_rate(year)
30+
if triple_lock.include_earnings(year) and triple_lock.include_inflation(
31+
year
32+
):
33+
triple_lock_increase = max(earnings_increase, cpi_increase, min_rate_y)
34+
elif triple_lock.include_earnings(year):
35+
triple_lock_increase = max(earnings_increase, min_rate_y)
36+
elif triple_lock.include_inflation(year):
37+
triple_lock_increase = max(cpi_increase, min_rate_y)
38+
else:
39+
triple_lock_increase = min_rate_y
3140
values[f"{year}-01-01"] = round(triple_lock_increase, 3)
3241

3342
new_parameter = Parameter(
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
description: Published triple lock uprating rates (outturn or DWP-announced). Used in preference to the max-of(earnings, CPI, minimum) formula because the formula relies on calendar-year OBR averages, while the actual uprating uses May-July AWE growth.
2+
values:
3+
2022-01-01: 0.031
4+
2023-01-01: 0.101
5+
2024-01-01: 0.085
6+
2025-01-01: 0.041
7+
2026-01-01: 0.048
8+
metadata:
9+
unit: /1
10+
label: Triple lock outturn rate
11+
reference:
12+
- title: DWP benefit and pension rates 2022 to 2023
13+
href: https://www.gov.uk/government/publications/benefit-and-pension-rates-2022-to-2023
14+
- title: DWP benefit and pension rates 2023 to 2024
15+
href: https://www.gov.uk/government/publications/benefit-and-pension-rates-2023-to-2024
16+
- title: DWP benefit and pension rates 2024 to 2025
17+
href: https://www.gov.uk/government/publications/benefit-and-pension-rates-2024-to-2025
18+
- title: DWP benefit and pension rates 2025 to 2026
19+
href: https://www.gov.uk/government/publications/benefit-and-pension-rates-2025-to-2026
20+
- title: DWP benefit and pension rates 2026 to 2027
21+
href: https://www.gov.uk/government/news/over-12-million-pensioners-to-receive-575-state-pension-boost
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
"""Verify the triple lock and downstream state pension amounts match published
2+
DWP / OBR uprating outturn for years where the actual rate is known.
3+
4+
Issue #953: previously the triple lock was computed from OBR calendar-year
5+
average earnings growth, which differs from the May-July AWE window DWP uses
6+
for the actual triple lock. That left every uprating year ~0.5-1.2pp off.
7+
"""
8+
9+
import pytest
10+
11+
from policyengine_uk.system import system
12+
13+
14+
# (year, expected uprating rate). Sources are linked in
15+
# parameters/gov/dwp/state_pension/triple_lock/outturn.yaml.
16+
OUTTURN_RATES = [
17+
(2022, 0.031),
18+
(2023, 0.101),
19+
(2024, 0.085),
20+
(2025, 0.041),
21+
(2026, 0.048),
22+
]
23+
24+
# (year, expected weekly £). Cross-referenced against gov.uk benefit and
25+
# pension rates publications.
26+
BASIC_STATE_PENSION_WEEKLY = [
27+
(2024, 169.50),
28+
(2025, 176.45),
29+
(2026, 184.90),
30+
]
31+
32+
NEW_STATE_PENSION_WEEKLY = [
33+
(2024, 221.20),
34+
(2025, 230.25),
35+
(2026, 241.30),
36+
]
37+
38+
39+
@pytest.mark.parametrize("year, expected", OUTTURN_RATES)
40+
def test_triple_lock_yoy_matches_published_outturn(year, expected):
41+
"""The generated triple lock yoy parameter should equal the DWP-announced
42+
rate for years where outturn is known."""
43+
yoy = system.parameters.gov.economic_assumptions.yoy_growth.triple_lock(
44+
f"{year}-01-01"
45+
)
46+
assert yoy == pytest.approx(expected, abs=1e-3)
47+
48+
49+
@pytest.mark.parametrize("year, expected", BASIC_STATE_PENSION_WEEKLY)
50+
def test_basic_state_pension_matches_published_rate(year, expected):
51+
weekly = system.parameters.gov.dwp.state_pension.basic_state_pension.amount(
52+
f"{year}-04-01"
53+
)
54+
assert weekly == pytest.approx(expected, abs=0.01)
55+
56+
57+
@pytest.mark.parametrize("year, expected", NEW_STATE_PENSION_WEEKLY)
58+
def test_new_state_pension_matches_published_rate(year, expected):
59+
weekly = system.parameters.gov.dwp.state_pension.new_state_pension.amount(
60+
f"{year}-04-01"
61+
)
62+
assert weekly == pytest.approx(expected, abs=0.01)

0 commit comments

Comments
 (0)