Skip to content

Anchor the Microcosm primary's ageing at its 2025 calibration year - #40

Merged
MaxGhenis merged 3 commits into
mainfrom
microcosm-anchor-calibration-year
Oct 26, 2026
Merged

MaxGhenis merged 3 commits into
mainfrom
microcosm-anchor-calibration-year

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Draft; round-3 review pending at 7a9afa2. This corrects the Microcosm primary's static-ageing anchor from 2024 to 2025, its calibration year. It's a fact error in the a133f37a registry entry from #37, not a change of method.

The bug

The registry's rule (METHOD.md, Household weights; the datasets.DATASETS comment) is that a dataset anchors at its build's calibration year. The rake keeps the dataset's own weights through the anchor, so it never moves the calibrated weights. #37 anchored microcosm_uk_2024_25@a133f37a at its 2024 data year, saying "no calibration year is declared for this cut". The cut's own release says otherwise:

  • build_record.json, uk_national_export_readback: weight_year: {dataset_year: 2024, solve_year: 2025, engine_projection_factor: 1.0072}.
  • microcosm's weight_year.py (microcosm#796 A19): the release writes the solved household weights divided by policyengine-uk's own projection of household_weight from the dataset year to the solve year, "so the engine returns the solved weights at the solve year". It is the same mechanism as the Enhanced FRS, without uk-data#538's offset.
  • calibration_diagnostics.json (in the release): all 1,259 targets are dated 2025; run_config.calibration_year is 2025.

So the model's 2025 weights are a133f37a's calibrated weights. With a 2024 anchor, the rake replaced them, and every later year's, with the 2024 weights grown by ONS age/sex cell growth. That is the move the rule exists to prevent.

The fix

  • ageing_anchor for a133f37a: {year: 2025, calibration_year: 2025}, citing the evidence above.
  • The release wording (pipeline.method_limitations), engine.py's and demography's notes (resolve_anchor and the module docstring), METHOD.md (outside the frozen C2 section) and a superseded note in CALIBRATION_ANCHOR.md.
  • The wording keeps the solved-weight identity to Microcosm. The Enhanced FRS's 2025 runtime weights are its calibrated ones times 0.9956 (policyengine-uk-data#538; METHOD.md, "The Enhanced FRS calibration year's level"), so the release wording says each dataset's own runtime weights are kept through the anchor. The exact identity holds only for builds from microcosm#1095 on: the 5c6b3f68 cross-check (microcosm 64c460b) stores its solved weights undivided, so its 2025 weights are the solved ones times 1.0072, every 2025 total 0.72% high. METHOD's level note now says so.
  • No engine change. demography.population already adds the anchor year to the years it builds, as for the Enhanced FRS.

d2011's a6299504 cut (#39) has the same build record (solve_year 2025, factor 1.0072, all 1,268 targets dated 2025), so #39 takes the same anchor.

Impact

No binding Microcosm run exists: #715's pair is unreleased, and the bridge's data step has not run. The published pre-Budget release used Enhanced FRS 1.58.0, already anchored at 2025, and its receipts are unchanged. So no published or recorded result moves. The binding rebuild's Microcosm weights in 2025 and later change from ONS-raked 2024 weights to the calibrated 2025 weights raked from 2025.

Invariants

  • Every registry entry with a calibration year anchors at it (new parametrized test over datasets.DATASETS).
  • Through the anchor, every year's weights are the dataset's own, exactly. This was already property-tested in test_demography; it is now also checked on the invented Microcosm-style dataset for both 2024 and 2025.

Verification

All on the locked UK 2.147.2 / core 3.33.3 environment.

  • At 7a9afa2 (round-2 fix): test_datasets, test_microcosm_primary, test_c2_screen, test_demography: 110 passed. The frozen C2 section is byte-identical to main.
  • At 8901d55 (the round-1 fix): test_microcosm_primary and test_datasets: 32 passed. CI: Pipeline and Dashboard pass.
  • At 4edb1c0: test_microcosm_primary and test_datasets: 26 passed.
  • The anchor-, ageing- and method-text-related set (16 files: test_ageing_model, test_ageing_report, test_c2_screen, test_datasets, test_demography, test_engine_pure, test_hb_allowance_diagnostic, test_matched_total_driver, test_microcosm_primary, test_model_v2_determinism, test_quoted_sensitivity, test_results, test_rules, test_scenarios, test_state_pension_age_addition, test_uncertainty): 692 passed, 3 failed. The 3 are the documented pre-build stale-results checks that scripts/check_prebuild_tests.py admits (test_results::test_not_stale, test_results::test_assumptions_block_is_current, test_scenarios::test_not_stale), each with its admitted message. The committed outputs predate the binding rebuild, as on main.
  • CI runs the full suite.
  • Independent review: GPT-6.1 Sol on 4edb1c0 supported the 2025 anchor and asked for the two wording fixes in 8901d55. Round 2 on 8901d55 found the identity still given to every Microcosm cut (5c6b3f68 predates #1095); 7a9afa2 scopes it. Round 3 is pending.
  • No survey or Microcosm simulation was run.

🤖 Generated with Claude Code

The a133f37a registry entry anchored static ageing at the 2024 data year,
saying no calibration year was declared for the cut. Its own build says
otherwise: it solves the household weights at 2025 and writes them at the
data year divided by policyengine-uk's 2024-to-2025 projection of
household_weight (build_record.json export readback weight_year: dataset
2024, solve 2025, factor 1.0072; microcosm weight_year.py, #796 A19), and
calibration_diagnostics.json dates all 1,259 targets 2025. So the model's
2025 weights are the solved ones, as the Enhanced FRS's are its calibrated
ones, and a 2024 anchor made the rake replace them with 2024 weights grown
by ONS cell growth. The anchor is now 2025, as the registry's rule (a
build's calibration year is its anchor) requires. A new test holds that
rule for every registry entry.

No binding Microcosm run exists yet, so no result moves.

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

vercel Bot commented Oct 25, 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 26, 2026 12:35am UTC

Request Review

MaxGhenis added a commit that referenced this pull request Oct 25, 2026
Cherry-picks #40 (4edb1c0) onto the bind, and applies the same correction to
d2011's a6299504. Each build solves its household weights at 2025 and
writes them at the 2024 data year divided by policyengine-uk's own
2024-to-2025 projection (build_record.json export readback weight_year:
dataset 2024, solve 2025, factor 1.0072; microcosm weight_year.py, #796
A19). Its calibration_diagnostics.json dates every target 2025 (1,259 for
a133f37a, 1,268 for a6299504). So the model's 2025 weights are the solved
ones, and the registry's rule (a build's calibration year is its anchor)
puts both anchors at 2025. a133f37a's entry had said no calibration year
was declared. A new test holds that rule for every registry entry.

No binding Microcosm run exists yet, so no result moves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… weights are calibrated x 0.9956

Review of 4edb1c0: the release wording and the a133 registry note called both
datasets' 2025 weights the calibrated ones, but METHOD.md's Enhanced FRS level
note (policyengine-uk-data#538) gives runtime = calibrated x 0.9956. demography's
module note still said the binding Microcosm cut anchors at 2024.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of 8901d55: demography's note gave the identity to every Microcosm
cut, but 5c6b3f68 (built at microcosm 64c460b) predates #1095's division by
the model's projection factor, so its 2025 weights are its solved ones times
1.0072. METHOD's level note and CALIBRATION_ANCHOR's superseded note now say
which builds divide, and that 5c6b3f68 also anchors at 2025 (since 95732e2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis
MaxGhenis marked this pull request as ready for review October 26, 2026 04:18
@MaxGhenis
MaxGhenis merged commit f47493e into main Oct 26, 2026
6 checks passed
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Merge audit (head 7a9afa2d3dd25fce9f6de0c58502d4865b536c45).

  • Independent review, three rounds:
    • Round 1 (4edb1c0): REQUEST_CHANGES. The text called the Enhanced FRS's 2025 runtime weights its calibrated ones; they are calibrated × 0.9956 (policyengine-uk-data#538).
    • Round 2 (8901d55, Opus while the Codex lanes were closed): REQUEST_CHANGES. The exact solved-weight identity held only for builds from microcosm#1095 on; 5c6b3f68 predates it, so its 2025 weights are solved × 1.0072.
    • Round 3 (7a9afa2, GPT-6.1 Sol, hard tier): APPROVE, no defects. It verified that weight_year.py is absent at microcosm 64c460b, added by #1095 (0f0bb869a), and byte-identical at 829c1bc. It also verified the 0.72% statement from policyengine-uk's household-weight projection.
  • Tests and protected material:
    • The reviewer's local run: 109 passed. The one failure was a Hypothesis timing deadline under host load, in the unchanged test_demography.py::test_payable_reports_and_components_add_up_for_every_record; it passes with the deadline off, and in CI.
    • Protected bytes and AST checks: 5 of 5 passed.
    • The frozen C2 block is identical to main.
  • CI: every check passes on the latest run at this head.
  • Scope:
    • This is a methodology-text and registry correction. Every Microcosm cut anchors static ageing at its 2025 calibration year, and the solved-weight identity is scoped to the builds it holds for.
    • No published number changes here: the binding rebuild has not run.
    • expected_value.py, redact_records/RECORD_FIELDS, handoffs and receipts are untouched.
    • It shares no files with Review policyengine-uk 2.151.0 as an exact Budget wheel beside 2.147.2 #38.
  • Gates:
    • checks green on the latest run;
    • MERGEABLE, not a draft, no CHANGES_REQUESTED review;
    • the hard review approves this exact head;
    • merged with a merge commit.

🤖 Generated with Claude Code

MaxGhenis added a commit that referenced this pull request Oct 26, 2026
Both conflicts resolve to this branch's side: the #40 text it cherry-picked, with
a6299504 named, and the pair's re-pointed registry entry. #38's final LBTT and
#2129/#2569 audit wording comes from main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis
MaxGhenis deleted the microcosm-anchor-calibration-year branch October 26, 2026 05:37

This branch was successfully deployed

1 active deployment
Preview — 7a9afa2d Deployed Oct 26, 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