Skip to content

Model v2: age the pension population with anchored ONS inputs - #23

Merged
MaxGhenis merged 28 commits into
model-v2from
model-v2-ageing
Oct 5, 2026
Merged

MaxGhenis merged 28 commits into
model-v2from
model-v2-ageing

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Survey ages and pension types remain fixed in forecast runs, so pensioner counts and the basic/new mix cannot follow projected retirement cohorts. This adds opt-in static ageing through one engine preparation hook, with the implementation in demography.py and cohorts.py. Household weights follow bounded entropy calibration to ONS 2024-based age/sex growth; top-coded records receive deterministic represented ages; pension types follow the legal birth-cohort cutoffs. Additional pension/protected residuals follow September CPI identically under both pension rules.

Draft against main; retarget onto part A's model-v2 (#24) before integration. Merge nothing. Addresses #14 section 3 and #9 A3. The committed dashboard remains on the legacy treatment.

The complete pilot ran 205 fresh full-model treatment jobs: central plus the exact 40 distinct Microcosm-paired expected-value selections, each under legacy/frozen/reweight/types/both, all on Enhanced FRS. It uses policyengine 5.3.0 / policyengine-uk 2.90.2, selected before part A was available. All pilot savings and coverage below are Great Britain, excluding Northern Ireland; the dashboard headline covers the UK.

2039–40 paired expected saving, £bn ± path SE Frozen Reweight Types Both Interaction
Gross 8.042 ± 0.057 9.765 ± 0.070 8.842 ± 0.063 10.723 ± 0.077 0.158 ± 0.001
Net 5.130 ± 0.089 6.165 ± 0.136 5.708 ± 0.091 6.858 ± 0.137 0.115 ± 0.002

The interaction is both − reweight − types + frozen, paired within paths. Central combined saving is only £0.854bn gross / £0.566bn net. Combined GB total State Pension spending is £129.152bn against matched DWP £148.269bn in 2026–27, and £149.556bn against £174.065bn in 2030–31. Ageing raises savings on this bundle but does not cure its baseline coverage gap.

Full annual results, central/expected four-way tables and DWP comparisons, design and remaining gates, calibration-source audit.

Validation: 366 regression tests passed, with two version-specific skips. The newest saved guard and renderer runs passed 70 and 219 tests respectively (.cache/ageing-publication-final-tests.log and .cache/ageing-renderer-final-tests.log). Those two synthetic oracle tests separately passed on policyengine-uk 2.118.0/core 3.32.16; the saved log explicitly records 188 records × 16 years = 3,008 exact cohort-type comparisons (.cache/ageing-upstream-oracle-final-tests.log). No survey data or fiscal runs were used for these oracles. Five fresh full-model control jobs, by construction, establish exact legacy central regression and persistent/isolated equivalence after one different legacy draw. All 3,936 raked-year checks passed, maximum relative error 3.13e-8. Publication verifies all 15 calculation source files against commit 217395208083401744b4325f9a0375d7ffb55574, hashes the publication code, and derives zero initial cache hits / 205 actual full-job completions from the original private log. Eight Enhanced FRS slots were requested; no Microcosm jobs ran.

The private audit checks same-year treatment differences, all pairs of years within each treatment, and changes in treatment contrasts between two years: 160 + 600 + 1,200 comparisons. Direct subtractions across both a different treatment and a different year are not separately enumerated. Age tables pass; all linked country/region tables are withheld. No survey weights, identifiers or record amounts are committed. Programme-derived nonlinear states remain outside the exhaustive pinned-input support proof and are disclosed.

María's gate 2 remains conditional and incomplete: the current-bundle mechanical checks pass, but calibrated-input preservation and the full coverage comparisons are unresolved. Runtime-native 2025 weights are unchanged at the verified source calibration-year anchor, but do not restore the builder's calibrated inputs; artifact-specific metadata is gated. Backward raking changes native 2024 data-year weights (GB State Pension £114.862bn under reweight versus £116.097bn frozen), so this is not data-year weight preservation. Eligible pension identity passes to the penny, but 40 positive below-pension-age reports keep the all-record identity open. Scottish pension-age winter heating and an explicit age-80 addition are absent upstream. Matched GB by-type/age/geography and post-2030 benchmarks are unavailable in the verified sources. Annual types are shared across rules but rebuilt once per path instead of persisted across paths. Part C must integrate the upgraded certified bundle, resolve the calibrated-input and State Pension/Pension Credit/Housing Benefit bridge, renew these validations and perform the separately scoped headline rebuild. The headline staleness test remains failing until that rebuild.

All mandatory independent-review findings, including N1–N6, are fixed. The standard, read-only Subfleet closeout 20261005-025509-ageing-closeout-review (private report .cache/ageing-closeout-independent-review.md), following approved postfix review 20261005-023519-ageing-postfix-review, approved the current-bundle evidence with no Critical, High or Medium findings and no required corrections. The refreshed audit records 1,960 support comparisons (160 + 600 + 1,200); age tables are available and the linked geography family is withheld. The saved exact-equality check confirms that the financial series and all 160 GB coverage rows from the 205 fiscal jobs remain unchanged from the originally approved publication. Both additional Info followups are closed: the central pension-bill table links to the backward-rake caveat, and the saved verbose renderer log records the committed source hashes and all 219 passing test names. Gate 2 remains conditional and incomplete; merge nothing.

The final focused independent Subfleet check (.cache/ageing-final-pointer-independent-review.md) approved both followups with no new required corrections. The root then remeasured the renderer and final JSON hashes and verified the original comparison baseline against its committed git blob. Final reviewed head: 0d042a34a8bb75009293a364e05d56663d4a5b30; final JSON SHA256: 8d3ce160b137f2affab2a92a9bc8501722baa2dddf6f49799f25670527ce66a3.

@vercel

vercel Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
uk-triple-lock Ready Ready Preview Oct 5, 2026 7:14am UTC

Request Review

@MaxGhenis
MaxGhenis changed the base branch from main to model-v2 October 5, 2026 08:39
@MaxGhenis
MaxGhenis merged commit 0085f6c into model-v2 Oct 5, 2026
3 of 4 checks passed
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Merged into model-v2 as merge commit 0085f6c, with its history kept. It is now part of #24, which stays a draft, and nothing is merged into main.

On model-v2 the ageing hook runs inside part A's engine, on policyengine-uk 2.120.0. It is the default treatment (both). The gates this PR left open are closed there:

  • Anchoring. The dataset's own weights are kept through the calibration year (2025), with no backward rake, and a property test covers it. The remaining 0.44% level gap is upstream, policyengine-uk-data#538.
  • Reports below State Pension age. They are not counted, because none is payable before pensionable age. The identity now holds for every record, and every run checks it.
  • Additional State Pension. One rule splits each year's report by that year's type, so cohort types pay nothing twice.
  • Population cache. It is shared across paths and read back against is_SP_age.
  • Upstream gaps.
    • The Scottish Pension Age Winter Heating Payment is modelled, contrary to AGEING_RULE_AUDIT.md, which is now corrected. Its winter-2025 rates are wrong upstream (policyengine-uk#2138).
    • The age addition is not modelled (policyengine-uk#2139).

The oracle tests pass on 2.120.0. The approved 2.90.2 pilot output and its renderer stay as the record. The worker and publication guard are retired, and the four-way design now runs on the engine's own jobs. The integrated pilot against this PR's numbers is in #24.

This branch was successfully deployed

1 active deployment
Preview — 0d042a34 Deployed Oct 5, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant