Skip to content

Model v2 C1: pre-register uncertainty screen, backtest five forms and gate full runs - #22

Merged
MaxGhenis merged 7 commits into
model-v2from
model-v2-uncertainty
Oct 5, 2026
Merged

MaxGhenis merged 7 commits into
model-v2from
model-v2-uncertainty

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

The expected saving currently relies on one shifted monthly VAR(1), while its dynamics range can depend on fewer than 100 effective runs. This C1 pilot freezes an adequacy screen before scoring five macro forms on held-out joint statutory inputs, with both April 2022 treatments and overlap-adjusted SEs.

None passes. All five cover only 1/6 chronological terminal policy gaps with published earnings (4/6 with the suspended leg). VAR(2)/Student-t also fail the published past-years percentile check; the annual bridge misses lead-switch thresholds. The implementation explicitly gates fiscal execution and disables the legacy 200-slot execution route until a C1 adapter consumes the 160-slot handoff, selects no replacement primary, and leaves the existing fiscal results unchanged.

Adds own-form draw/stratum/spec handoffs, paired primary earnings ±0.5pp from 2031 with identical shocks and indices, separate path-sampling/first-phase variance and ± for every year, low-effective-run range exclusion, and the Newton/Armijo root fix for #15. The 50,000 primary draws and mean paths are diagnostic only; all satisfy the rule guarantees. Its 2034–39 implied premium is 0.546454pp versus OBR 0.557167pp.

Validation: 65 pure Python uncertainty/method/estimator tests pass; all 150,000 diagnostic paths checked; 50,000 primary draws replay exactly (maximum error 0, within 1e-12) with scipy 1.18.1. No PolicyEngine microsimulation or survey data. Independent Subfleet review 20261004-223140-tl-c1-review completed: no high-severity findings, and the no-passing-form decision was confirmed. The execution-design, artifact reproduction and validation findings are addressed; the original report and limitations are committed.

Historical public full-run aggregates are re-estimated without survey records: 2034–35 gross £2.591bn ±£0.275bn / net £1.683bn ±£0.177bn; 2039–40 gross £8.411bn ±£0.091bn / net £5.392bn ±£0.074bn (±1.96 combined Monte Carlo SE). Means are unchanged; these conditional bands do not establish predictive adequacy. All historical dynamics rows show ± and effective-run counts, and rows below 100 are excluded from ranges.

See pre-registered method, scores and decisions, and committed diagnostic specs/manifests in docs/uncertainty/. Across-form/mean-path spread is a scenario envelope, never a probability interval; forms are not averaged.

Draft against main; retarget onto model-v2 before merging. Merge nothing here. Full rebuilding needs a C1 handoff adapter, updated macro inputs, an adequate passing form, the certified model/data bundle and the other model-v2 acceptance gates.

Addresses #14 section 4 / gate 3 and #9 A2; fixes #15.

@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 2:50am UTC

Request Review

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

Copy link
Copy Markdown
Contributor

Thanks Max: a careful pilot, and keeping the screen as pre-registered is the right call. This comes after the merge, so the points below are for model-v2.

  1. CI is red on model-v2. test_not_stale passes at the base commit, fails at this PR's head and still fails at b994a55. The source changes, including the tilt solver, weren't rebuilt into results.json. Please rebuild, or limit provenance to engine-affecting files and record why the historical results still stand.
  2. The pipeline can't run. pipeline.py:245 calls expected_value.build() with run=True, which now always raises: ValueError on a fail, NotImplementedError on a pass. The C1 adapter needs to be on the critical path before the post-Budget rebuild.
  3. Pre-registration. The rule commit (a8d2ac8) is 16 minutes before the scores, but both were first pushed together. Next round, could the rule be pushed, or put in an issue, before scoring? The later METHOD edits (abf733c, 9b177e1) should be labelled as post-scoring clarifications. I checked that no threshold changed.
  4. The headline failure is one episode, not six. With published earnings, origins 2017–21 miss. With the legal suspension, 2020–21 still miss: realised terminal gap 3.4–4.2pp against about 1pp forecast, from the 2022–23 surge. Terminal bias is negative, so the models understate the gap and the bands are too narrow. Worth saying in UNCERTAINTY_PILOT.md.
  5. The five forms aren't independent tests. All five share the OBR mean shift and the residual pool, and the monthly forms exclude COVID months, which is the kind of shock the screen fails on. Please cover that in the next pre-registration. The annual form's block misalignment was found after scoring and needs re-specifying.
  6. The suspended treatment. On it alone, VAR(1) bootstrap would pass (floor bias 0.241 against a 0.25 limit). That's a defensible primary for a policy-gap target, but only through a new pre-registered rule, never this one, with the deterministic-zero 2021 cell disclosed.
  7. The ±0.5pt mean-path runs shouldn't wait for the screen. They're a scenario, not a probability claim. The implementation itself is sound: the same shock hash and paired indices.
  8. First-phase SE for reweightings (stratified_estimate) should use the reweighted draws' effective sample size, not N=50,000. Either way the term is small (2039-40 gross ±£0.083bn → ±£0.091bn) and doesn't address Full review of triple lock modeling, dashboard, and PR #8 paper #9 A2.
  9. Flaky test: test_moment_tilt_hits_every_target_whatever_the_scale (tilt error just above 1e-6) #15: the fix is correct, a line-search change with @example pins that fail on the old solver. Flaky test: test_moment_tilt_hits_every_target_whatever_the_scale (tilt error just above 1e-6) #15 needs closing by hand once model-v2 reaches main.

On presentation, I'd suggest:

  • a central figure plus a labelled scenario range (the eligible dynamics rows, plus ±0.5pt), with no "80%" or "likely" wording;
  • the ± described as Monte Carlo precision of this path set only;
  • one sentence saying the macro model fails its own pre-registered backtest on 2020–23, in the direction of understating the gap.

Tests at 9b177e1 (policyengine-uk 2.90.2): 213 passed, with only test_not_stale failing, the same as CI.

@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Merged into model-v2 as merge commit 52b80bf, with its history kept, and now part of #24 (still a draft; nothing is merged into main).

C1's gate is unchanged: expected_value.build(run=True) refuses a form that failed the screen. It also refuses the legacy 200-slot route, even for a form that passes. The method decision is d955.

docs/REBUILD.md sets out what the rebuild needs:

  • the screen re-run on the post-Budget means and September CPI;
  • the C1 adapter for the 160-slot design;
  • the paired-subsample fields the four-way ageing design reads.

The merge also reconciles part B's estimator test with this PR's gross_share_flat_rate_spending_pct output.

This branch was successfully deployed

1 active deployment
Preview — 9b177e16 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.

Flaky test: test_moment_tilt_hits_every_target_whatever_the_scale (tilt error just above 1e-6)

2 participants