Skip to content

Commit 3cf4de8

Browse files
MaxGhenisclaude
andauthored
Fix state_pension_type classifying all pensioners as BASIC (#1618)
The formula used `sp.new_state_pension.active.values_list[0]` to find the instant the New State Pension was switched on (2016-01-01 under current law). policyengine-core auto-extrapolates values_list into the far future in newest→oldest order, so `[0]` was returning a 2040s entry instead of the activation instant. That made `years_since_instant` negative, pushing `male_age` / `female_age` down to ~51, so every pensioner was `over_age` → classified `BASIC` and nobody received the New State Pension. Walks the list oldest→newest and takes the first `True` value to get the real activation instant. Adds baseline YAML tests covering both BASIC and NEW classification on either side of the NSP activation. Verified against the latest enhanced FRS dataset: - BASIC pensioners: 12.06M → 7.36M weighted - NEW pensioners: 0.00M → 4.71M weighted - state_pension aggregate 2025: £116.2bn → £127.5bn Remaining gap to OBR (~£140bn) is additional State Pension coverage, outside this PR's scope. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent caadd1a commit 3cf4de8

3 files changed

Lines changed: 55 additions & 3 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Fix `state_pension_type` incorrectly classifying every pensioner as receiving the pre-2016 basic State Pension. The formula used `values_list[0]` to find when the New State Pension activated, but policyengine-core auto-extrapolates the parameter into the far future, so `[0]` was returning a 2040s entry instead of the 2016 activation date. Walks the list oldest-first to find the real activation instant, so post-2016 retirees are now correctly classified as `NEW`. Raises the modelled 2025 state pension aggregate from about £116bn to about £127bn.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
- name: Below State Pension age is NONE
2+
period: 2025
3+
input:
4+
age: 60
5+
is_male: true
6+
output:
7+
state_pension_type: NONE
8+
9+
- name: Male reaching SPA after NSP activation (age 70 in 2025, born 1955) gets NEW
10+
period: 2025
11+
input:
12+
age: 70
13+
is_male: true
14+
output:
15+
state_pension_type: NEW
16+
17+
- name: Male reaching SPA before NSP activation (age 80 in 2025, born 1945) gets BASIC
18+
period: 2025
19+
input:
20+
age: 80
21+
is_male: true
22+
output:
23+
state_pension_type: BASIC
24+
25+
- name: Female reaching SPA after NSP activation (age 70 in 2025, born 1955) gets NEW
26+
period: 2025
27+
input:
28+
age: 70
29+
is_male: false
30+
output:
31+
state_pension_type: NEW
32+
33+
- name: Female reaching SPA before NSP activation (age 80 in 2025, born 1945) gets BASIC
34+
period: 2025
35+
input:
36+
age: 80
37+
is_male: false
38+
output:
39+
state_pension_type: BASIC

policyengine_uk/variables/gov/dwp/state_pension_type.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,26 @@ class state_pension_type(Variable):
1818
def formula(person, period, parameters):
1919
sp = parameters.gov.dwp.state_pension
2020
male = person("is_male", period)
21-
last_entry = sp.new_state_pension.active.values_list[0]
2221
is_sp_age = person("is_SP_age", period)
23-
if not last_entry:
22+
23+
# Find the instant the New State Pension was first switched on.
24+
# values_list is ordered newest→oldest and PolicyEngine-core
25+
# auto-extrapolates it into the far future, so values_list[0] is a
26+
# future year's extrapolation rather than the activation date. Walk
27+
# oldest→newest and take the first `True` value to get the real
28+
# activation instant (e.g. 2016-01-01 under current law).
29+
activation_entry = None
30+
for entry in reversed(sp.new_state_pension.active.values_list):
31+
if entry.value:
32+
activation_entry = entry
33+
break
34+
35+
if activation_entry is None:
2436
values_if_sp_age = where(
2537
is_sp_age, StatePensionType.BASIC, StatePensionType.NONE
2638
)
2739
else:
28-
instant = last_entry.instant_str
40+
instant = activation_entry.instant_str
2941
years_since_instant = period.start.year - int(instant[:4])
3042
male_age = sp.age.male(instant) + years_since_instant
3143
female_age = sp.age.female(instant) + years_since_instant

0 commit comments

Comments
 (0)