Skip to content

State pension undershoot: -£12bn vs OBR, ASP/Protected Payment under-captured #1632

@MaxGhenis

Description

@MaxGhenis

Background

After PR #1618 fixed state_pension_type (BASIC vs NEW classification), the model's state pension aggregate is £127.5 bn vs the OBR 2025 target of ~£140 bn — still a -£12 bn gap, identified in tracking issue #1621 as the largest residual benefit aggregate misalignment.

Diagnosis

Two related pipeline limitations combine to understate the total:

1. new_state_pension pays flat max amount to every NEW-type retiree

Current formula in policyengine_uk/variables/gov/dwp/new_state_pension.py:

def formula(person, period, parameters):
    type = person("state_pension_type", period)
    eligible = type == type.possible_values.NEW
    p = parameters(period).gov.dwp.state_pension.new_state_pension
    return eligible * p.amount * WEEKS_IN_YEAR  # full amount for everyone

This ignores the reported amount entirely. In reality:

  • Under 35 NI years → pro-rated full amount
  • Over full rate (Protected Payment from pre-2016 SERPS/S2P) → higher than flat amount

The flat-max assumption over-states for partial-NI-record retirees and under-states Protected Payment for those with substantial pre-2016 SERPS contributions. The net effect on aggregate is ambiguous without data.

2. additional_state_pension only captures reported amounts exceeding max basic, for BASIC type

Current ASP formula in policyengine_uk/variables/gov/dwp/additional_state_pension.py:

reported = person("state_pension_reported", data_year) / WEEKS_IN_YEAR
type = person("state_pension_type", data_year)
# ...
amount_in_data_year = where(
    type == type.possible_values.BASIC,
    max_(reported - max_sp_data_year, 0),  # only BASIC
    0,
)

For BASIC-type retirees reporting exactly the max basic amount (£169/wk in 2024), this yields ASP = 0 — but many of those retirees in reality also received SERPS/S2P top-ups. FRS state_pension_reported is derived from SRP (the single weekly benefit value), which aggregates basic + ASP; if SRP is capped or rounded at the max basic, ASP is under-imputed.

Additionally, there's no Protected Payment component for NEW-type retirees anywhere in the pipeline.

Proposed fixes

Two options, both non-trivial:

  1. Formula-side — change new_state_pension to use state_pension_reported directly (with data-year uprating, matching the basic_state_pension / additional_state_pension pattern). This captures Protected Payment organically for NEW-type retirees who reported more than the flat max. Risk: reduces aggregate for partial-NI-record retirees whose reported is < max.

  2. Data-side — impute an ASP component on BASIC-type rows whose reported matches the max basic exactly. This requires breaking out SERPS/S2P coverage from an external source (ONS National Pensioners Survey or DWP administrative caseload by pension type).

Either approach needs empirical validation against OBR/DWP outturn for FY 2024-25. Filing for follow-up; too scoped to land in the current PR sweep.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions