Skip to content

State pension: respect recorded amount for 'new SP' cohort (mirror old-SP scaling) #59

@vahid-ahmadi

Description

@vahid-ahmadi

Bug

person_state_pension in src/variables/benefits.rs ignores the recorded person.state_pension value for the new SP cohort (those whose age is below basic_sp_min_age) and always returns the full parameter rate × 52.

The basic SP cohort branch correctly uses scaled-recorded-amount: it returns person.state_pension × (reform_rate / baseline_rate) if recorded, falling back to the parameter rate × 52 only when nothing is recorded.

The new SP branch should follow the same pattern.

Symptom (already measurable)

The parity harness in PR #53 shows a £946 divergence on the pensioner_couple synthetic scenario:

-- pensioner_couple --
  state_pension     rust=23,946  py=23,000  diff=946

Both pensioners have recorded state_pension: 11500 (totalling £23,000). Rust ignores those values and returns 2 × new_state_pension_weekly × 52 = 2 × £230.25 × 52 = £23,946. Python uses the recorded values. £946 = 2 × (£11,973 - £11,500).

Fix

Mirror the existing old-SP pattern, so that:

  1. If person.state_pension > 0: return that amount, scaled by (new_state_pension_weekly / baseline_new_sp_weekly) for reform-correctness
  2. If person.state_pension == 0: return new_state_pension_weekly × 52

This requires plumbing baseline_new_sp_weekly through Simulation::new and person_state_pension, parallel to the existing baseline_old_sp_weekly field.

Acceptance

  • Parity harness shows £0 state-pension diff on pensioner_couple (or matches Python's recorded-amount semantics)
  • Existing param_state_pension_new_weekly test still passes (it uses state_pension = 0 so reform behaviour unchanged on that path)
  • A new unit test asserts that when state_pension > 0, the recorded amount is returned (×1.0 in baseline) regardless of the new-SP parameter rate

Effort

Small — ~15 LOC + 2-3 unit tests + the YAML parity case.

Surfaces from

PR #53 parity harness — exactly the kind of regression the harness was designed to catch.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    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