Skip to content

Triple Lock post: the Budget's inputs (October forecast, 2.151.0, Microcosm) - #1493

Merged
MaxGhenis merged 20 commits into
mainfrom
triple-lock-post-budget-figures
Oct 31, 2026
Merged

MaxGhenis merged 20 commits into
mainfrom
triple-lock-post-budget-figures

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

This updates the live Triple Lock explainer (uk-triple-lock-budget-2026) from pre-Budget figures to the Budget's inputs, using the final binding results.

PolicyEngine/uk-triple-lock#49 merged at 12:08Z on 31 October as merge commit 728c63f, at head 9d99213. Merging it deployed the dashboard, and this PR follows it straight away.

Max approved this wording on 31 October (d2223, "Yes, merge both", which also covers d2228), at 3cbb480. The branch now holds exactly that text plus the date line: git diff 3cbb480 6fbf051 shows one line, "Updated 31 October 2026". A later rewrite that names the actors moved to branch triple-lock-post-actors and goes to Max separately. The diff since his earlier go shows every edit he approved.

Source

Every PolicyEngine figure comes from uk-triple-lock's final file, data/results.json at 9d99213, on PolicyEngine/uk-triple-lock#49 (sha256 22c57248). That file uses:

  • the OBR's October 2026 EFO to 2030, then its March 2026 long-term determinants (d2124);
  • PolicyEngine UK 2.151.0 (policyengine.py 6.11.1) on Microcosm UK 2024-25 (a6299504);
  • scenarios only: the model failed C2 on one check, so d955(a) applied automatically.

#49's head moved from 0b47c87 to 9d99213 before it merged, which changed the dashboard's label to "160 simulated draws", says a model must pass on both sets of past forecasts and names each set as one forecast a year. None of these moves touches the results file or the replay's inputs. At merge commit 728c63f, both copies of the results file keep blob 614334a1 (sha256 22c57248) and the inputs keep 0cc4a39e, so both links stay pinned to 9d99213, an ancestor of that merge commit, and each returns 200.

What changes

Pre-Budget (live) This PR
Central path, 2039-40 gross / net £0.9bn / £0.6bn £0.5bn / £0.3bn
OBR long-term assumption, gross / net £10.3bn / £7.3bn £10.9bn / £7.3bn
GB, central / assumption £0.8bn / £10.0bn £0.5bn / £10.6bn
Full new State Pension gap (assumption) £865 a year £836 a year
State Pension counted against DWP 15% less 2% less (£144.8bn vs £148.3bn)
Replay from 2017, 2026-27 £653, 5.2% £642, 5.1% (ONS October vintage)
Households losing (assumption) 27% 30%, by £801 on average; fewer than 1 in 300 gain

From the interim draft, only the OBR long-term assumption scenario moved: 31 figure occurrences, including the pensioner poverty rates (10.6% to 11.4% relative, 6.7% to 7.4% absolute). All central-path, replay and backtest figures held.

Prose changes:

  • Top note: names the Budget's inputs, links the results file, and says the dashboard draws on it. The old-name footnote goes.
  • Central-path table: now on the October path. April 2028 is 3.4%, and the two rules meet again in April 2033, not 2034.
  • Gross to net: a new sentence says the steps do not sum exactly once rounded (£10.9bn − £2.4bn − £0.8bn − £0.3bn gives £7.4bn against a stated £7.3bn).
  • Poverty: new baselines, and overall relative poverty AHC now falls (19.3% to 19.1%). The relative line is 60% of the contemporary median (policyengine-uk 2.151.0 in_relative_poverty_ahc).
  • Methodology: the d2124 vintage mix, the OBR's April to June earnings and September-quarter CPI as proxies, and Microcosm as the data. It dates the long-term row from April 2032 and states how the two earnings scenarios use the model.
  • New passage: the dashboard's two further scenarios and three single paths, so the post covers everything the dashboard shows. Quoted below.
  • Sample size: the binding design holds 160 draws of 159 distinct paths (draw 34965 falls twice), and the estimator leaves check draw 21 out. The post now says "160 draws". The withdrawn average's "160 paths" stands, because that build had 160 distinct paths.
  • Second set of forecasts: the post described only the seven March forecasts, while the registered test uses two sets and a model must pass on both. A new sentence says the model passed every check on the second set: 13 OBR forecasts, one a year, from June 2010 to March 2022 (docs/C2_BINDING.md: "Test B passes every check"). "Every check" means the checks C2 scores, which use April 2022 as the law set it. complete_statutory_origins keeps one spring forecast a year, so the OBR's other forecasts of those years fall outside the set.
  • Voice: the post carries Max's byline, so the full voice_max.md gate ran over the post and its description. Be-verb comparisons became comparing verbs, reduced passives name their actor, unclear pronouns name their noun, and the description drops "We explain how". The OBR's row phases in the extra 0.6 points, so the post now credits the OBR.

New passage

Our dashboard also shows two scenarios from the model's paths, with calendar-year earnings growth targets 0.5 percentage points lower or higher from 2031. State Pension spending falls by an estimated average of £11.4 billion in 2039-40 with lower earnings growth and £11.9 billion with higher, each with a 95% Monte Carlo margin of about £0.5 billion. Both averages come from the model that failed the test, like the average we withdrew. We estimate each from full runs on 160 draws and weight the results to stand for all 50,000 paths. The failed test does not show whether these averages overstate or understate the saving, and we do not use either average as a forecast. The dashboard also shows three single paths as illustrations, which save between £11.3 billion and £19.8 billion in 2039-40.

Holds

  • Figure ledger on the final file, at this head: 129 of 129 class A figures and 74 replay figures MATCH, 41 of 41 claim checks PASS, exit 0. check_passage.py in ~/reviews/uk-triple-lock-explainer/ledger-v2/ runs the ledger on the post without the new passage, then checks the passage's figures against the file: every one matches.
  • The earlier obr_wedge hold cleared: d40796c is in the final file, and the wedge-description checks now pass at every April.
  • Delta review of this update at 1735181, on Opus 5.5 (20261030-131127-tl-final-delta): APPROVE. It recomputed all 31 changed figures from the file and tied the approval to the merge order above.
  • New passage: round 1 on Opus 5.5 CHANGES, round 2 on GPT-6.1 Sol CHANGES, both applied. Two points were not taken as first proposed:
    • Round 1 wanted "may overstate the saving". Round 2 agreed with rejecting it: the model under-predicted the terminal gap in Test A (0.99% against 1.44%) and over-predicted it in Test B (1.17% against 0.92%), so the failed test shows no direction.
    • Round 2 offered a shorter sentence in place of "those years come more often". The passage drops it instead, because the section already gives the mechanism.
  • Investigate high number of chunk requests #49's candidate final head: 0b47c87 rebuilds the file from cache with new wording only. A recursive diff against 26fbc89 gives 12 changed leaves (eight wording, four provenance) and no other number. Both links now pin 0b47c87, and the file behind the replay link keeps its blob (0cc4a39e). The post uses none of the old labels, no run counts and no Enhanced FRS wording.
  • GPT-6.1 Sol confirmation of the post with the passage at 161066e, with main merged in (20261030-145914-tl-head-check, ~/reviews/uk-triple-lock-explainer/final-delta/head-check/review-head.md): APPROVE, no findings. It recomputed every figure in the passage from the file, recalculated the margins from the variance components, rebuilt the central and OBR assumption savings from totals, and confirmed that rounds 1 and 2 are resolved. It could not rebuild the weighted means from individual runs, because the file holds no run-level outputs.
  • Ledger on the 0b47c87 file (blob 614334a1) at this head: 129 MATCH, 41 PASS, every passage check PASS, exit 0.
  • GPT-6.1 Sol delta review of the move to 0b47c87 at 8de2d24 (20261030-164212-tl-0b47c87, ~/reviews/uk-triple-lock-explainer/final-delta/0b47c87/review-0b47c87.md): APPROVE, no findings. It diffed the two files itself: 12 changed text leaves and none of the 74,509 numeric leaves moved. It recalculated the margins, rebuilt the central, OBR assumption and single-path savings from totals, and tested the new wording against the post. It could not run the dashboard or rebuild the weighted means from individual runs.
  • Investigate high number of chunk requests #49 at d4e94d1: both blobs unchanged. The commit changes four test files, one Method tab heading and one METHOD.md sentence.
  • GPT-6.1 Sol on the sample size (20261030-203722-tl-d4e94d1-160): CHANGES. It counted 160 draws, 159 distinct paths and one check run outside the estimate, and passed the withdrawn average's "160 paths".
  • GPT-6.1 Sol on the wording edits and the whole-post voice gate (20261030-204627-tl-1493-voice): CHANGES, applied except where it named the wrong actor. docs/METHOD.md says the OBR's row phases in the 0.6 points, and the rule, not PolicyEngine, raises the pension.
  • GPT-6.1 Sol final check at 12578a0 (20261030-210043-tl-1493-voice2, ~/reviews/uk-triple-lock-explainer/final-delta/d4e94d1/voice2/review-final.md): APPROVE, no findings. It could not rerun PolicyEngine, rebuild the averages from individual runs or recheck external sources.
  • Investigate high number of chunk requests #49 at 631d10f: both blobs unchanged, including the dashboard's copy of the results file.
  • GPT-6.1 Sol on the second-set sentence at b882289 (20261030-211732-tl-1493-second-set, ~/reviews/uk-triple-lock-explainer/final-delta/631d10f/review-second-set.md): APPROVE, no findings. The repo's owner confirmed the sentence separately against data/results.json at 631d10f.
  • Investigate high number of chunk requests #49 at e6afafb: both blobs unchanged, including the dashboard's copy of the results file.
  • Investigate high number of chunk requests #49 at 9d99213: three documentation files changed and nothing under src/, dashboard/, tests/ or data/. Both blobs unchanged, including the dashboard's copy of the results file.
  • Investigate high number of chunk requests #49's owner review of 9d99213: APPROVE, no findings. Both links pinned at 3cbb480, and the diff from 88c0940 touches only the two commit hashes. Both URLs return 200.
  • Sentence fix at 88c0940. "The 13 OBR forecasts" read as if the OBR made only 13 in that span, and the two checks above passed it. The sentence now says "13 OBR forecasts, one a year". Lines 231 and 250 say "March forecasts", which stays true.
  • GPT-6.1 Sol on the corrected sentence at 88c0940 (20261030-213106-tl-1493-one-a-year, ~/reviews/uk-triple-lock-explainer/final-delta/e6afafb/review-one-a-year.md): APPROVE, no findings. The brief asked it to count the forecasts, test every line that describes a set of them and gate the sentence against voice_max.md.
  • GPT-6.1 Sol whole-post voice gate at 88c0940 (20261030-213743-tl-1493-voice-88c0940, ~/reviews/uk-triple-lock-explainer/final-delta/e6afafb/review-voice-whole.md): APPROVE, no findings. It read all 706 lines of voice_max.md and gated the post, chart text, title and description.
  • Ledger at this head on blob 614334a1: 129 MATCH, 41 PASS, every passage check PASS, exit 0.
  • Max's go on the figures: d2212, "Include the passage".
  • Max's go on this wording: d2223, ruled 31 October at 3cbb480 ("Yes, merge both").
  • Both links repinned to Investigate high number of chunk requests #49's final head, with the results blob confirmed.
  • Investigate high number of chunk requests #49 merged at 12:08Z as merge commit 728c63f, at head 9d99213. Results blob 614334a1 in both copies and inputs blob 0cc4a39e unchanged, and the dashboard returns 200.
  • Ledger at 6fbf051, the approved text plus the date line: 129 MATCH, 41 PASS, 22 passage checks PASS, exit 0.

Checks

  • All four chart blocks parse as JSON at this head, and website/src/__tests__/components/blog-chart-posts.test.ts passes (8 tests).

🤖 Generated with Claude Code

…rocosm)

Every PolicyEngine figure now comes from uk-triple-lock's scenarios-first
file at 94d3bb6d (#49): the OBR's October 2026 forecast to 2030 with its
March 2026 long-term determinants after (d2124), PolicyEngine UK 2.151.0
and Microcosm UK 2024-25. Scenarios only, as under ruling (a).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
policyengine-calculator-next Ready Ready Preview Oct 31, 2026 12:10pm UTC
policyengine-website Ready Ready Preview Oct 31, 2026 12:10pm UTC

Request Review

MaxGhenis and others added 3 commits October 29, 2026 09:29
… (Sol r8)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…osing

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…et-figures

# Conflicts:
#	app/src/data/posts/articles/uk-triple-lock-budget-2026.md
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 2 commits October 30, 2026 13:02
Read every figure from the binding results file at uk-triple-lock
26fbc89. Only the OBR long-term assumption scenario moves: £10.9bn gross
and £836 a year in 2039-40, with its household, decile and poverty
figures. Point the file links at that commit, date the update 30 October,
and say that the gross-to-net steps do not sum exactly once rounded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The dashboard shows four scenario cards once uk-triple-lock#49 merges, so the
post now covers the two earnings scenarios and the three single paths, per
Max's ruling on d2212. The top note says the results file feeds the dashboard,
the old-name footnote goes, and the methodology dates the long-term row from
April 2032.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
0b47c87 rebuilds the results file with new wording only; the post's
figures all match it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 2 commits October 30, 2026 20:45
The binding sample holds 160 draws of 159 distinct paths, so "160 paths"
overstated the paths by one. "160 draws" states the sample the estimator
uses and still matches the dashboard's count. The figures do not move.

The rest applies the full voice gate to the post and its description:
be-verb comparisons become comparing verbs, reduced passives name their
actor, and the description drops a clause about the post itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Name the model where "it" could have meant the withdrawn average, and
keep the voice gate's sentence lengths. The figures do not move.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Restore the "no range" point, name the model that failed the test, and
fix the pronouns and reduced passives the review listed. The OBR's own
row phases in the extra 0.6 points, so the post credits the OBR. The
figures do not move.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The registered test uses two sets, and a model must pass on both. The
post named only the seven March forecasts, while the dashboard now
names both. The second set's 13 forecasts run from June 2010 to March
2022, and the model passed every check on them. No figure moves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The test keeps one spring forecast a year, so "the 13 OBR forecasts"
read as if the OBR made only 13 in that period. No figure moves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both links move from 0b47c87 to 9d99213. The results and inputs
files keep their blobs, so no figure or word changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Make the government, Parliament and the Work and Pensions Secretary the subjects where they act, and "we" in the replay and scenario set-up. Add what section 150A requires, what the government adds, how the rise reaches law, and that the adjusted Triple Lock needs legislation. Name gross State Pension spending where the rule-as-subject wording said "saves". Tidy a loose "it" and a "So" after a pass.

No figure changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Cut the claim about which Parliament approves the first adjusted rise, which the election deadline does not establish. Give the replay to "we", in the present tense, because it is our hypothetical run. Move model and method sentences to "we" and "the model", introduce ONS, and keep gross figures as State Pension spending.

No figure changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
d2223 approved the wording at 3cbb480, so this PR lands exactly that text. The actor rewrite moves to its own branch, triple-lock-post-actors, for Max's go. Sets the date line to 31 October.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis
MaxGhenis marked this pull request as ready for review October 31, 2026 12:09
@MaxGhenis
MaxGhenis merged commit 17db3a3 into main Oct 31, 2026
10 checks passed
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Merged at 12:14Z as 17db3a3 with --admin. The required approving review was the only block, and every check passed at head 6fbf051.

  • Max's go: d2223, "Approve the reworded post at 3cbb480". Investigate high number of chunk requests #49 merged first as d2228 directs (728c63f, a true merge commit with parent 9d99213).
  • Text: this head equals 3cbb480 plus the date line, which now reads 31 October. git diff 3cbb480 6fbf0519 shows that one line.
  • Pins: data/results.json and dashboard/public/data/results.json kept blob 614334a1, and data/triple_lock_actual_inputs.csv kept blob 0cc4a39e. Both 9d99213 links return 200, so no repin.
  • Ledger at this head: 129 MATCH, 41 PASS, 22 passage PASS, 0 FAIL.
  • Reviews: Sol head check 20261030-145914, Sol 20261030-213106-tl-1493-one-a-year, Sol voice 20261030-213743-tl-1493-voice-88c0940, owner delta 13.
  • Live check: production returned 200 with "Updated 31 October 2026" and the post-Budget figures once both Vercel deployments finished, and the rendered page reads correctly in a browser.

The rewrite that names who acts (triple-lock-post-actors) adds new legal claims, so d2223 doesn't cover it. It stays out of this merge and goes to Max as its own PR.

@MaxGhenis
MaxGhenis deleted the triple-lock-post-budget-figures branch October 31, 2026 12:35

This branch was successfully deployed

2 active deployments
Preview – policyengine-website — 6fbf0519 Deployed Oct 31, 2026 by vercel[bot]
Preview – policyengine-calculator-next — 6fbf0519 Deployed Oct 31, 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