Skip to content

Calibrate the UK national build from Ledger-backed targets #623

Closed

Description

@juaristi22

Depends on: #622 (compiled registry + parity gate) and a UK national calibration seam, which does not exist yet — the national staging path is gate-only by design. This issue is the convergence point, filed now so the seam work and the target migration land against a shared contract.

Context

Today's UK national build (tools/build_uk_national_dataset.py → build_uk_national_dataset) runs two stages (frs_hmrc_retained_leaves, hmrc_spi_income), enforces coverage/terminal gates, and stages an H5 — explicitly without calibration: the terminal report omits the target-surface/target-fit/parity trio "instead of inventing passes". The June production release's 149-target national calibration ran from code that never reached a pushed branch; its surface is being ported to Ledger (PolicyEngine/chronicle#132, PolicyEngine/chronicle#133) and its compilation to populace (#622).

The local lane already shows the target shape end to end (ladder targets → local_doctrine solve → diagnostics). This issue gives the national build the same property, with Ledger as the only source of target values.

Scope

  1. National calibration seam — a stage (or post-stage step) in the UK national build that accepts a compiled TargetRegistry and produces calibrated household weights, advancing household_weight_kind and appending the canonical mass-change record, mirroring the rowwise candidate path's conventions (build_uk_rowwise_candidate.py).
  2. Ledger-backed surface only — the seam consumes the registry compiled in Consume Ledger UK facts: uk_target_references, mapping module, and a compile-parity gate #622 (hash-pinned consumer artifact + uk_target_references.json active subset). No target value may enter from any other path; the uk-data package is not a build dependency.
  3. Solver doctrine — reuse populace.calibrate (the shared L0/solve stack) under a declared national doctrine analogous to local_doctrine.py: uniform operator, declared caps, no per-target knobs. The doctrine constants land in a reviewed module, not as CLI flags.
  4. Evidence becomes real — with a calibration present, the terminal-gate battery gains the previously-omitted trio: target-surface, target-fit (existing UK_MAX_TARGET_ABS_RELATIVE_ERROR = 0.25 fence), and parity evidence; uk_calibration_diagnostics_payload gets wired with the Ledger pin (facts sha256, profile ids) in its provenance block.
  5. Acceptance against the incumbent — the US base v2: one CPS+ACS+PUF-detail pool; datasets labeled by exact record count (dense = full pool; exact-k L0 selection) #578 acceptance rule stands: the first Ledger-calibrated candidate must not regress the certified June artifact on battery observables (ESS fraction ≥ 0.01 fence, weight-ratio fence, target-fit). Score against the frozen reference exactly as the terminal gates already encode it.

Explicitly out of scope

  • Base-table construction, imputations, or any change to what the input H5 is (separate workstream).
  • Ledger authoring or profile changes.
  • Retiring uk-data's own calibration pipeline — uk-data remains the production builder until a Ledger-calibrated populace candidate passes the acceptance battery; this issue produces that candidate, not the switchover decision.

Acceptance

  • A UK national staging build with the seam armed produces a calibrated H5 whose terminal report carries the full gate battery (no omitted trio), with every target value traceable through ledger_facts_sha256 → consumer artifact → source package → publisher bytes.
  • The build fails hard if the compiled registry and the release's pinned Ledger artifact disagree (no mixed-provenance surfaces).
  • Candidate-vs-incumbent scoring reproduces the production diagnostics schema (score_vs_enhanced_frs-style block) so the release decision is comparable to June's.

Activity

  1. juaristi22 commented on Aug 14, 2026

    @juaristi22
    CollaboratorAuthor

    Adjudication request from WS-E planning: the incumbent's post-calibration aggregate scalers (2026-08-14)

    The incumbent runs four aggregate adjustments after calibration, on weighted sums: rail-subsidy scaling to the ORR total, bus-subsidy scaling to the DfT total, fuel-litre-proxy scaling to HMRC road-fuel clearances, and the bus-fare rescale that also reshapes the income gradient to NTS trips-per-quintile. Because they read calibrated weights, they cannot live in the WS-E source stages — the ports (#682 consumption/services, #685 bus fares) deliberately exclude them and impute incidence + amounts only.

    They need a home on this seam. Two candidate dispositions, per family:

    1. Re-express as calibration targets where a chronicle fact family exists or can exist (rail/bus subsidy totals, road-fuel volumes) — the solver then does what the post-hoc scaler did, with provenance.
    2. A D-side post-calibration stage with an explicit mass-change/value-change record for anything that is genuinely a post-weight transform (the NTS income-gradient reshape is the awkward one — it rewrites household values conditioned on weighted quantiles, not weights).

    Related: the WS-E/WS-D grain adjudication is #688; the WS-E child map is on #145. No action needed until #685 opens, but flagging now so the target-registry design (#622) can reserve the families if disposition 1 wins.

  2. MaxGhenis commented on Aug 20, 2026

    @MaxGhenis
    Contributor

    Picking up the core of this per #701: the national calibrate step consuming activated ledger-backed references, with loud resolution failures (no silent drops — the policyengine-uk-data#456 defect class) and the existing gate discipline. The 2026-08-14 post-calibration aggregate-scaler adjudication stays explicitly OUT of scope — that ruling remains open and yours; the calibrate step lands without porting any incumbent scalers.

  3. juaristi22 commented on Aug 22, 2026

    @juaristi22
    CollaboratorAuthor

    Status: narrowed to run-readiness — delivered by #743 (draft); the licensed armed run is held

    Per #736 item 10 and the adjudicated plan (2026-08-21), mapping this issue's scope to delivery:

    1. Seam — core landed in Add the UK national calibration step over ledger-backed target references #729; UK national calibration run-readiness: doctrine, live parity trio, US-format diagnostics, scorer, staging posture (#623) #743 completes the conventions: canonical mass-change record naming the bound families, post-solve CALIBRATED/mass fences, household_weight_kind_chain + calibration_mass_change manifest block.
    2. Ledger-only surface — Complete #622: compile the UK target surface from Ledger facts at the 2024-25 line #735's compiled registry is the single compile path; the stage materializes it at frs_release.calibration_year (2025) through the shared adapter, fail-closed.
    3. Doctrine — uk_runtime/national_doctrine.py (v1 = Add the UK national calibration step over ledger-backed target references #729's values, declared + tamper-tested; revision requires a receipt).
    4. Evidence trio + provenance — armed builds produce real uk_export_surface/uk_target_surface/uk_target_fit verdicts from independently sourced sides (frozen eFRS instrument + declared registry at name@period grain); unarmed builds keep evidence_absent. Diagnostics are US-format-identical (shared producer, format-parity pin) with the chronicle pin (ledger_facts_sha256, manifest sha, profile ids) in the build block.
    5. Acceptance vs incumbent — tools/score_uk_national_candidate.py rescores both artifacts on one frozen register (US base v2: one CPS+ACS+PUF-detail pool; datasets labeled by exact record count (dense = full pool; exact-k L0 selection) #578 rule 1), June-schema score_vs_enhanced_frs block; the real score is produced by the held run.

    The run itself is held until the WS-E spine completes E8 (#684) + E10 (#686), or an explicitly named different base — runbook in docs/uk-national-calibration-runbook-623.md. The 2026-08-14 post-calibration aggregate-scaler adjudication remains open on this issue (per Max's 2026-08-20 comment); first-run evidence on those families becomes input to that ruling. This issue stays open until the held run executes and its acceptance evidence lands.

  4. juaristi22 commented on Aug 26, 2026

    @juaristi22
    CollaboratorAuthor

    Status against this issue's own acceptance criteria (2026-08-26)

    Measured after #747/#743 merged and the #757 swap branch (PR #787) retired the June path.

    Delivered in full — scope items 1–3:

    Delivered in substance — scope item 4: the parity trio evaluates for real on armed builds from independently sourced sides; diagnostics are US-format-identical with chronicle provenance (ledger_facts_sha256 → artifact → source, acceptance a's traceability half). Live proofs on the migrated seam: 403 targets bound at 2025 (+25 over the assessment campaign, none dropped), correctly blocking at uk_target_fit on the known catalogue; four binding defects found and fixed from those runs (obr.ni −76.7% → −2.9% among them).

    Open — the three pieces keeping this issue alive:

    1. The US base v2: one CPS+ACS+PUF-detail pool; datasets labeled by exact record count (dense = full pool; exact-k L0 selection) #578 acceptance receipt (scope 5 / acceptance c): tools/score_uk_national_candidate.py exists with the June-schema block, but no production seam run has been scored against the incumbent — score_vs_enhanced_frs is still reserved null in every build record. Produced by the first certified cut (Swap the microcosm-built UK spine into the national build and retire the incumbent feed #757 follow-up, Phase 3).
    2. The full-battery terminal report (acceptance a): "no omitted trio" on one report is the multi-part certification (B5) — the seam deliberately runs its 6-gate scope and marks shippable: false until the certification exists. Same Swap the microcosm-built UK spine into the national build and retire the incumbent feed #757 follow-up.
    3. The post-calibration aggregate-scaler adjudication (2026-08-14, still open) — now extracted to Adjudicate the incumbent's four post-calibration aggregate scalers #790 so the ruling survives this issue closing: the four scalers, the port/target/exclude options per scaler, and the new evidence that the fuel-litre scaler and Swap the microcosm-built UK spine into the national build and retire the incumbent feed #757's obr.fuel_duties disposition (frame carries ~37% of implied litres) are the same question from two sides.

    Closure path: items 1–2 land with the #757 follow-up's certified cut; this issue can close on that PR, with #790 carrying the scaler ruling and #736 the remaining deferred-decision registry.

    🤖 Posted with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions